texlive[64251] Master/texmf-dist: l3kernel (31aug22)

commits+karl at tug.org commits+karl at tug.org
Wed Aug 31 22:19:45 CEST 2022


Revision: 64251
          http://tug.org/svn/texlive?view=revision&revision=64251
Author:   karl
Date:     2022-08-31 22:19:45 +0200 (Wed, 31 Aug 2022)
Log Message:
-----------
l3kernel (31aug22)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/l3kernel/CHANGELOG.md
    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/interface3.tex
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3doc.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3docstrip.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news01.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news02.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news03.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news04.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news05.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news06.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news07.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news08.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news09.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news10.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news11.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3news12.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3prefixes.pdf
    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/l3term-glossary.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/l3term-glossary.tex
    trunk/Master/texmf-dist/doc/latex/l3kernel/source3.pdf
    trunk/Master/texmf-dist/doc/latex/l3kernel/source3.tex
    trunk/Master/texmf-dist/doc/latex/l3kernel/source3body.tex
    trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3.ins
    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/l3cctab.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/l3debug.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/l3expan.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3file.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/l3fparray.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3legacy.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/l3pdf.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/l3regex.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-convert.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/l3text-case.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3text.dtx
    trunk/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.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/l3kernel/l3unicode.dtx
    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.ltx
    trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty

Added Paths:
-----------
    trunk/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/CHANGELOG.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/CHANGELOG.md	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/CHANGELOG.md	2022-08-31 20:19:45 UTC (rev 64251)
@@ -7,6 +7,17 @@
 
 ## [Unreleased]
 
+## [2022-08-30]
+
+### Added
+- `\pdf_object_new:n` and `\pdf_object_write:nnn` - support assignment of object
+  type at point-of-writing (issue
+  [\#1123](https://github.com/latex3/latex3/issues/1123))
+- `\text_map_function:nN` and `\text_map_inline:nn` for mapping to
+  graphemes in textual input
+- Support for medevial Latin case changing
+- `\char_to_nfd:n` to extend NFD support to 8-bit engines
+
 ## [2022-08-23]
 
 ### Added
@@ -1188,7 +1199,8 @@
 - Step functions have been added for dim variables,
   e.g. `\dim_step_inline:nnnn`
 
-[Unreleased]: https://github.com/latex3/latex3/compare/2022-08-23...HEAD
+[Unreleased]: https://github.com/latex3/latex3/compare/2022-08-30...HEAD
+[2022-08-30]: https://github.com/latex3/latex3/compare/2022-08-23...2022-08-30
 [2022-08-23]: https://github.com/latex3/latex3/compare/2022-08-05...2022-08-23
 [2022-08-05]: https://github.com/latex3/latex3/compare/2022-07-15...2022-08-05
 [2022-07-15]: https://github.com/latex3/latex3/compare/2022-07-14...2022-07-15

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/README.md	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/README.md	2022-08-31 20:19:45 UTC (rev 64251)
@@ -1,7 +1,7 @@
 LaTeX3 Programming Conventions
 ==============================
 
-Release 2022-08-23
+Release 2022-08-30
 
 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/interface3.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/interface3.tex	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/interface3.tex	2022-08-31 20:19:45 UTC (rev 64251)
@@ -54,7 +54,7 @@
          {latex-team at latex-project.org}%
    }%
 }
-\date{Released 2022-08-23}
+\date{Released 2022-08-30}
 
 \pagenumbering{roman}
 \maketitle

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3doc.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/l3news.pdf
===================================================================
(Binary files differ)

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

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

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

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

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

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

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

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

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

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

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

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

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

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	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.tex	2022-08-31 20:19:45 UTC (rev 64251)
@@ -32,7 +32,7 @@
         {latex-team at latex-project.org}%
     }%
 }
-\date{Released 2022-08-23}
+\date{Released 2022-08-30}
 
 \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	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.tex	2022-08-31 20:19:45 UTC (rev 64251)
@@ -32,7 +32,7 @@
         {latex-team at latex-project.org}%
     }%
 }
-\date{Released 2022-08-23}
+\date{Released 2022-08-30}
 
 \newcommand{\TF}{\textit{(TF)}}
 

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

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/l3term-glossary.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/l3term-glossary.tex	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/l3term-glossary.tex	2022-08-31 20:19:45 UTC (rev 64251)
@@ -32,7 +32,7 @@
         {latex-team at latex-project.org}%
     }%
 }
-\date{Released 2022-08-23}
+\date{Released 2022-08-30}
 
 \newcommand{\TF}{\textit{(TF)}}
 

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

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/source3.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/source3.tex	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/source3.tex	2022-08-31 20:19:45 UTC (rev 64251)
@@ -53,7 +53,7 @@
          {latex-team at latex-project.org}%
    }%
 }
-\date{Released 2022-08-23}
+\date{Released 2022-08-30}
 
 \pagenumbering{roman}
 \maketitle

Modified: trunk/Master/texmf-dist/doc/latex/l3kernel/source3body.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/l3kernel/source3body.tex	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/doc/latex/l3kernel/source3body.tex	2022-08-31 20:19:45 UTC (rev 64251)
@@ -589,6 +589,7 @@
 \clist_gput_right:Nn \g_docinput_clist
   {
     l3text-case.dtx ,
+    l3text-map.dtx  ,
     l3text-purify.dtx
   }
 \ExplSyntaxOff

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/expl3.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -24,7 +24,7 @@
 %
 %<*driver|generic|package|2ekernel>
 %</driver|generic|package|2ekernel>
-\def\ExplFileDate{2022-08-23}%
+\def\ExplFileDate{2022-08-30}%
 %<*driver>
 \documentclass[full]{l3doc}
 \usepackage{graphicx}
@@ -51,7 +51,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3.ins
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3.ins	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3.ins	2022-08-31 20:19:45 UTC (rev 64251)
@@ -106,6 +106,7 @@
         \from{l3unicode.dtx}    {package}
         \from{l3text.dtx}       {package}
         \from{l3text-case.dtx}  {package}
+        \from{l3text-map.dtx}   {package}
         \from{l3text-purify.dtx}{package}
         \from{l3candidates.dtx} {package}
         \from{l3legacy.dtx}     {package}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3box.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %
@@ -643,11 +643,23 @@
 %     \cs{char_to_nfd:N} \meta{char}
 %   \end{syntax}
 %   Converts the \meta{char} to the Unicode Normalization Form Canonical
-%   Decomposition. The category code of the generated character is the
-%   same as the \meta{char}. With $8$-bit engines, no change is made to the
-%   character.
+%   Decomposition. The category code of the \emph{first} generated character is
+%   the same as the \meta{char}; second and subsequent chars will have the
+%   current category code, as they would if typed in directly. For $8$-bit
+%   engines, no change will take place.
 % \end{function}
 %
+% \begin{function}[added = 2022-08-29, rEXP]{\char_to_nfd:n}
+%   \begin{syntax}
+%     \cs{char_to_nfd:n} \Arg{codepoint}
+%   \end{syntax}
+%   Converts the (Unicode) \meta{codepoint} to the Unicode Normalization
+%   Form Canonical Decomposition. The generated character(s) will have
+%   the current category code as they would if typed in directly. In contrast
+%   to \cs{char_to_nfd:N}, this function \emph{does} decompose codepoints
+%   with $8$-bit engines.
+% \end{function}
+%
 % \begin{function}[added = 2018-09-23]
 %   {
 %     \peek_catcode_collect_inline:Nn,

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3color.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -85,7 +85,7 @@
 %    require you to do updates, if the class changes.}}
 %
 % \author{\Team}
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 % \maketitle
 % \tableofcontents
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -63,7 +63,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3file.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 % \maketitle
 %
 % \begin{documentation}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 % \maketitle
 %
 % \begin{documentation}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -40,7 +40,7 @@
 %          {latex-team at latex-project.org}^^A
 %    }^^A
 % }
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -49,7 +49,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3int.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3names.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %
@@ -51,33 +51,19 @@
 %
 % \section{Objects}
 %
-% \begin{function}[added = 2021-02-10]{\pdf_object_new:nn}
+% \begin{function}[added = 2022-08-23]{\pdf_object_new:n}
 %   \begin{syntax}
-%     \cs{pdf_object_new:nn} \Arg{object} \Arg{type}
+%     \cs{pdf_object_new:n} \Arg{object}
 %   \end{syntax}
-%   Declares \meta{object} as a PDF object of \meta{type}, which should be
-%   one of
-%   \begin{itemize}
-%     \item \texttt{array}
-%     \item \texttt{dict}
-%     \item \texttt{fstream}
-%     \item \texttt{stream}
-%   \end{itemize}
-%   The object may be referenced from this point on, and written later
-%   using \cs{pdf_object_write:nn}.
+%   Declares \meta{object} as a PDF object. The object may be referenced
+%   from this point on, and written later using \cs{pdf_object_write:nnn}.
 % \end{function}
-% \begin{function}[EXP, pTF, added=2020-05-15]{\pdf_object_if_exist:n}
+%
+% \begin{function}[added = 2022-08-23]
+%   {\pdf_object_write:nnn, \pdf_object_write:nnx}
 %   \begin{syntax}
-%    \cs{pdf_object_if_exist_p:n} \Arg{object}
-%    \cs{pdf_object_if_exist:nTF} \Arg{object}
+%     \cs{pdf_object_write:nn} \Arg{object} \Arg{type} \Arg{content}
 %   \end{syntax}
-%   Tests whether an object with name \Arg{object} has been defined.
-% \end{function}
-% \begin{function}[added = 2021-02-10]
-%   {\pdf_object_write:nn, \pdf_object_write:nx}
-%   \begin{syntax}
-%     \cs{pdf_object_write:nn} \Arg{object} \Arg{content}
-%   \end{syntax}
 %   Writes the \meta{content} as content of the \meta{object}. Depending on the
 %   \meta{type} declared for the object, the format required for the
 %   \meta{data} will vary
@@ -133,6 +119,14 @@
 %   Inserts the appropriate information to reference the \meta{pageobject}.
 % \end{function}
 %
+% \begin{function}[EXP, pTF, added = 2020-05-15]{\pdf_object_if_exist:n}
+%   \begin{syntax}
+%    \cs{pdf_object_if_exist_p:n} \Arg{object}
+%    \cs{pdf_object_if_exist:nTF} \Arg{object}
+%   \end{syntax}
+%   Tests whether an object with name \Arg{object} has been defined.
+% \end{function}
+%
 % \section{Version}
 %
 % \begin{function}[pTF, EXP, added = 2021-02-10]{\pdf_version_compare:Nn}
@@ -250,6 +244,46 @@
 % \end{function}
 % \end{documentation}
 %
+% \section{Deprecated functions}
+%
+% \begin{function}[added = 2021-02-10]{\pdf_object_new:nn}
+%   \begin{syntax}
+%     \cs{pdf_object_new:nn} \Arg{object} \Arg{type}
+%   \end{syntax}
+%   Declares \meta{object} as a PDF object of \meta{type}, which should be
+%   one of
+%   \begin{itemize}
+%     \item \texttt{array}
+%     \item \texttt{dict}
+%     \item \texttt{fstream}
+%     \item \texttt{stream}
+%   \end{itemize}
+%   The object may be referenced from this point on, and written later
+%   using \cs{pdf_object_write:nn}.
+%
+%   Deprecated in favor of \cs{pdf_object_new:n}.
+% \end{function}
+%
+% \begin{function}[added = 2021-02-10]{\pdf_object_write:nn, \pdf_object_write:nx}
+%   \begin{syntax}
+%     \cs{pdf_object_write:nn} \Arg{object} \Arg{content}
+%   \end{syntax}
+%   Writes the \meta{content} as content of the \meta{object}. Depending on the
+%   \meta{type} declared for the object, the format required for the
+%   \meta{data} will vary
+%   \begin{itemize}
+%     \item[\texttt{array}] A space-separated list of values
+%     \item[\texttt{dict}] Key--value pairs in the form
+%       \texttt{/\meta{key} \meta{value}}
+%     \item[\texttt{fstream}] Two brace groups: \meta{file name} and
+%       \meta{file content}
+%     \item[\texttt{stream}] Two brace groups: \meta{attributes (dictionary)}
+%       and \meta{stream contents}
+%   \end{itemize}
+%
+%  Deprecated in favor of \cs{pdf_object_write:nnn}.
+% \end{function}
+%
 % \begin{implementation}
 %
 % \section{\pkg{l3pdf} implementation}
@@ -306,27 +340,28 @@
 %
 % \subsection{Objects}
 %
-% \begin{macro}{\pdf_object_new:nn, \pdf_object_write:nn, \pdf_object_write:nx}
-% \begin{macro}[pTF]{\pdf_object_if_exist:n}
+% \begin{macro}{\pdf_object_new:n}
+% \begin{macro}{\pdf_object_write:nnn, \pdf_object_write:nnx}
 % \begin{macro}{\pdf_object_ref:n}
 % \begin{macro}{\pdf_object_unnamed_write:nn, \pdf_object_unnamed_write:nx}
 % \begin{macro}{\pdf_object_ref_last:}
-%   Simple to do.
+% \begin{macro}[pTF]{\pdf_object_if_exist:n}
+%   Simple to do: all objects create a constant |int| so it is not a
+%   backend-specific name.
 %    \begin{macrocode}
-\cs_new_protected:Npn \pdf_object_new:nn #1#2
-  { \@@_backend_object_new:nn {#1} {#2} }
-\prg_new_conditional:Npnn \pdf_object_if_exist:n #1 { p , T , F , TF }
+\cs_new_protected:Npn \pdf_object_new:n #1
   {
-    \int_if_exist:cTF { c_@@_backend_object_ \tl_to_str:n {#1} _int }
-     { \prg_return_true: }
-     { \prg_return_false:}
+    \@@_backend_object_new:n {#1}
+    \cs_new_eq:cc
+      { c_@@_backend_object_ \tl_to_str:n {#1} _int }
+      { c_@@_object_ \tl_to_str:n {#1} _int }
   }
-\cs_new_protected:Npn \pdf_object_write:nn #1#2
+\cs_new_protected:Npn \pdf_object_write:nnn #1#2#3
   {
-    \@@_backend_object_write:nn {#1} {#2}
+    \@@_backend_object_write:nnn {#1} {#2} {#3}
     \bool_gset_true:N \g_@@_init_bool
   }
-\cs_generate_variant:Nn \pdf_object_write:nn { nx }
+\cs_generate_variant:Nn \pdf_object_write:nnn { nnx }
 \cs_new:Npn \pdf_object_ref:n #1 { \@@_backend_object_ref:n {#1} }
 \cs_new_protected:Npn \pdf_object_unnamed_write:nn #1#2
   {
@@ -335,6 +370,12 @@
   }
 \cs_generate_variant:Nn \pdf_object_unnamed_write:nn { nx }
 \cs_new:Npn \pdf_object_ref_last: { \@@_backend_object_last: }
+\prg_new_conditional:Npnn \pdf_object_if_exist:n #1 { p , T , F , TF }
+  {
+    \int_if_exist:cTF { c_@@_object_ \tl_to_str:n {#1} _int }
+      \prg_return_true:
+      \prg_return_false:
+  }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -341,6 +382,7 @@
 % \end{macro}
 % \end{macro}
 % \end{macro}
+% \end{macro}
 %
 % \begin{macro}{\pdf_pageobject_ref:n}
 %    \begin{macrocode}
@@ -450,7 +492,35 @@
   }
 %    \end{macrocode}
 % \end{macro}
+%
+% \subsection{Deprecated functions}
+%
+% \begin{variable}{\g_@@_object_prop}
+%   For tracking objects.
 %    \begin{macrocode}
+\prop_new:N \g_@@_object_prop
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\pdf_object_new:nn, \pdf_object_write:nn, \pdf_object_write:nx}
+%   Wrap up the type data in a prop.
+%    \begin{macrocode}
+\cs_new_protected:Npn \pdf_object_new:nn #1#2
+  {
+    \prop_gput:Nnn \g_@@_object_prop {#1} {#2}
+    \@@_backend_object_new:n {#1}
+  }
+\cs_new_protected:Npn \pdf_object_write:nn #1#2
+  {
+    \exp_args:Nnx \@@_backend_object_write:nnn
+      {#1} { \prop_item:Nn \g_@@_object_prop {#1} } {#2}
+    \bool_gset_true:N \g_@@_init_bool
+  }
+\cs_generate_variant:Nn \pdf_object_write:nn { nx }
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macrocode}
 %</package>
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3str.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %
@@ -1435,6 +1435,40 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[EXP]{\@@_change_case_lower_la-x-medieval:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_la-x-medieval:nnnN}
+%   Simply swaps of characters.
+%    \begin{macrocode}
+\cs_new:cpn { @@_change_case_lower_la-x-medieval:nnnN } #1#2#3#4
+  {
+    \int_compare:nNnTF { `#4 } = { `V }
+      {
+        \@@_change_case_store:e
+          {
+            \char_generate:nn { `u } { \@@_char_catcode:N #4 }
+          }
+        \use:c { @@_change_case_char_next_ #2 :nn }
+          {#2} {#3}
+      }
+      { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+  }
+\cs_new:cpn { @@_change_case_upper_la-x-medieval:nnnN } #1#2#3#4
+  {
+    \int_compare:nNnTF { `#4 } = { `u }
+      {
+        \@@_change_case_store:e
+          {
+            \char_generate:nn { `V } { \@@_char_catcode:N #4 }
+          }
+        \use:c { @@_change_case_char_next_ #2 :nn }
+          {#2} {#3}
+      }
+      { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
 % \begin{macro}[EXP]
 %   {
 %     \@@_change_cases_lower_lt:nnnN      ,

Added: trunk/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx	                        (rev 0)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -0,0 +1,586 @@
+% \iffalse meta-comment
+%
+%% File: l3text-map.dtx
+%
+% Copyright (C) 2022 The LaTeX 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
+%
+%    https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3kernel 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>
+\documentclass[full,kernel]{l3doc}
+\begin{document}
+  \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+%   The \textsf{l3text-map} package: text processing (mapping)^^A
+% }
+%
+% \author{^^A
+%  The \LaTeX{} Project\thanks
+%    {^^A
+%      E-mail:
+%        \href{mailto:latex-team at latex-project.org}
+%          {latex-team at latex-project.org}^^A
+%    }^^A
+% }
+%
+% \date{Released 2022-08-30}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3text-map} implementation}
+%
+%    \begin{macrocode}
+%<*package>
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=text>
+%    \end{macrocode}
+%
+% \subsection{Mapping to text}
+%
+% \begin{macro}[EXP]{\text_map_function:nN}
+% \begin{macro}[EXP]{\@@_map_function:nN}
+% \begin{macro}[EXP]{\@@_map_loop:Nnw}
+% \begin{macro}[EXP]{\@@_map_group:Nnn}
+% \begin{macro}[EXP]{\@@_map_space:Nnw}
+% \begin{macro}[EXP]{\@@_map_N_type:NnN}
+% \begin{macro}[EXP]{\@@_map_codepoint:Nnn}
+% \begin{macro}[EXP]{\@@_map_CR:Nnw}
+% \begin{macro}[EXP]{\@@_map_CR:NnN}
+% \begin{macro}[EXP]{\@@_map_class:Nnnn}
+% \begin{macro}[EXP]{\@@_map_class:nNnnn}
+% \begin{macro}[EXP]{\@@_map_class_loop:Nnnnw}
+% \begin{macro}[EXP]{\@@_map_class_end:nw}
+% \begin{macro}[EXP]
+%   {
+%     \@@_map_Control:Nnn     ,
+%     \@@_map_Extend:Nnn      ,
+%     \@@_map_SpacingMark:Nnn ,
+%     \@@_map_Prepend:Nnn     ,
+%     \@@_map_Prepend_aux:Nnn
+%   }
+% \begin{macro}[EXP]{\@@_map_Prepend:nNnn}
+% \begin{macro}[EXP]{\@@_map_Prepend_loop:Nnnw}
+% \begin{macro}[EXP]
+%   {
+%     \@@_map_not_Control:Nnn     ,
+%     \@@_map_not_Extend:Nnn      ,
+%     \@@_map_not_SpacingMark:Nnn ,
+%     \@@_map_not_Prepend:Nnn     ,
+%     \@@_map_not_L:Nnn           ,
+%     \@@_map_not_LV:Nnn          ,
+%     \@@_map_not_V:Nnn           ,
+%     \@@_map_not_LVT:Nnn         ,
+%     \@@_map_not_T:Nnn
+%   }
+% \begin{macro}[EXP]
+%   {
+%     \@@_map_L:Nnn   ,
+%     \@@_map_LV:Nnn  ,
+%     \@@_map_V:Nnn   ,
+%     \@@_map_LVT:Nnn ,
+%     \@@_map_T:Nnn
+%   }
+% \begin{macro}[EXP]{\@@_map_hangul:Nnnw}
+% \begin{macro}[EXP]{\@@_map_hangul:NnnN}
+% \begin{macro}[EXP]{\@@_map_hangul:Nnnn}
+% \begin{macro}[EXP]{\@@_map_hangul_aux:Nnnnw}
+% \begin{macro}[EXP]{\@@_map_hangul:nNnnnw}
+% \begin{macro}[EXP]{\@@_map_hangul_loop:Nnnnnw}
+% \begin{macro}[EXP]{\@@_map_hangul_next:Nnnn}
+% \begin{macro}[EXP]{\@@_map_hangul_end:nw}
+% \begin{macro}[EXP]
+%   {
+%     \@@_map_hangul_L:Nnn   ,
+%     \@@_map_hangul_LV:Nnn  ,
+%     \@@_map_hangul_V:Nnn   ,
+%     \@@_map_hangul_LVT:Nnn ,
+%     \@@_map_hangul_T:Nnn
+%   }
+% \begin{macro}[EXP]
+%   {\@@_map_Regional_Indicator:Nnn, \@@_map_Regional_Indicator_aux:Nnn}
+% \begin{macro}[EXP]{\@@_map_lookahead:NnNw}
+% \begin{macro}[EXP]{\@@_map_lookahead:NnNN}
+% \begin{macro}[EXP]{\@@_map_output:Nn}
+% \begin{macro}[EXP]{\text_map_break:}
+% \begin{macro}[EXP]{\text_map_break:n}
+%   The standard lead-off for an action loop.
+%    \begin{macrocode}
+\cs_new:Npn \text_map_function:nN #1#2
+  { \exp_args:Ne \@@_map_function:nN { \text_expand:n {#1} } #2 }
+\cs_new:Npn \@@_map_function:nN #1#2
+  {
+    \@@_map_loop:Nnw #2 { } #1
+      \q_@@_recursion_tail \q_@@_recursion_stop
+    \prg_break_point:Nn \text_map_break: { }
+  }
+%    \end{macrocode}
+%  The standard set up for an \enquote{action} loop. Groups are handled by
+%  recursion, spaces are treated similarly: both count as grapheme boundaries.
+%  For \texttt{N}-type tokens, we filter out control sequences (again
+%  a boundary), then move on to further analysis.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_loop:Nnw #1#2#3 \q_@@_recursion_stop
+  {
+    \tl_if_head_is_N_type:nTF {#3}
+      { \@@_map_N_type:NnN }
+      {
+        \tl_if_head_is_group:nTF {#3}
+          { \@@_map_group:Nnn }
+          { \@@_map_space:Nnw }
+      }
+    #1 {#2} #3 \q_@@_recursion_stop
+  }
+\cs_new:Npn \@@_map_group:Nnn #1#2#3
+  {
+    \@@_map_output:Nn #1 {#2}
+    {
+      \@@_map_loop:Nnw #1 { } #2
+        \q_@@_recursion_tail \q_@@_recursion_stop
+      \prg_break_point:Nn \text_map_break: { }
+    }
+    \@@_map_loop:Nnw #1 { }
+  }
+\use:x
+  { \cs_new:Npn \exp_not:N \@@_map_space:Nnw ##1##2 \c_space_tl }
+  {
+    \@@_map_output:Nn #1 {#2}
+    #1 { ~ }
+    \@@_map_loop:Nnw #1 { }
+  }
+\cs_new:Npn \@@_map_N_type:NnN #1#2#3
+  {
+    \@@_if_q_recursion_tail_stop_do:Nn #3
+      {
+        \@@_map_output:Nn #1 {#2}
+        \text_map_break:
+      }
+    \token_if_cs:NTF #3
+      {
+        \@@_map_output:Nn #1 {#2}
+        #1 {#3}
+        \@@_map_loop:Nnw #1 { }
+      }
+      {
+        \@@_codepoint_process:nN
+          { \@@_map_codepoint:Nnn #1 {#2} } #3
+      }
+  }
+%    \end{macrocode}
+%  We pull out a few special cases here. Carriage returns case needs a bit of
+%  context handling so has an auxiliary. Codepoint U+200D is the zero-width
+%  joiner, which has no context to concern us: just don't break.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_codepoint:Nnn #1#2#3
+  {
+    \@@_codepoint_compare:nNnTF {#3} = { "0D }
+      {
+        \@@_map_output:Nn #1 {#2}
+        \@@_map_CR:Nnw #1 {#3}
+      }
+      {
+        \@@_codepoint_compare:nNnTF {#3} = { "200D }
+          { \@@_map_loop:Nnw #1 {#2#3} }
+          { \@@_map_class:Nnnn #1 {#2} {#3} { Control } }
+      }
+  }
+%    \end{macrocode}
+%   A carriage return is a boundary unless it is immediately followed by
+%   a line feed, in which case that pair is a boundary.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_CR:Nnw #1#2#3 \q_@@_recursion_stop
+  {
+    \tl_if_head_is_N_type:nTF {#3}
+      { \@@_map_CR:NnN #1 {#2} }
+      {
+        #1 {#2}
+        \@@_map_loop:Nnw #1 { }
+      }
+        #3 \q_@@_recursion_stop
+  }
+\cs_new:Npn \@@_map_CR:NnN #1#2#3
+  {
+    \@@_if_q_recursion_tail_stop_do:Nn #3
+      {
+        #1 {#2}
+        \text_map_break:
+      }
+    \bool_lazy_and:nnTF
+      { ! \token_if_cs_p:N #3 }
+      { \int_compare_p:nNn { `#3 } = { "0A } }
+      {
+        \@@_map_output:Nn #1 {#2#3}
+        \@@_map_loop:Nnw #1 { }
+      }
+      { \@@_map_loop:Nnw #1 { } #3 }
+  }
+%    \end{macrocode}
+%   There are various classes of character, and we deal with them all in
+%   the same general way. We need to example the relevant list of codepoints:
+%   if we get a hit, then we do whatever the relevant action is. Otherwise
+%   we loop, but only if the current codepoint could still match: the
+%   loop stops early otherwise and we move forward.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_class:Nnnn #1#2#3#4
+  {
+    \exp_args:Nv \@@_map_class:nNnnn { c_@@_grapheme_ #4 _clist }
+      #1 {#2} {#3} {#4}
+  }
+\cs_new:Npn \@@_map_class:nNnnn #1#2#3#4#5
+  {
+    \@@_map_class_loop:Nnnnw #2 {#3} {#4} {#5}
+      #1 , \q_@@_recursion_tail .. , \q_@@_recursion_stop
+  }
+\cs_new:Npn \@@_map_class_loop:Nnnnw #1#2#3#4 #5 .. #6 ,
+  {
+    \@@_if_q_recursion_tail_stop_do:nn {#5}
+      { \use:c { @@_map_not_ #4 :Nnn } #1 {#2} {#3} }
+    \@@_codepoint_compare:nNnTF {#3} < { "#5 }
+      {
+        \@@_map_class_end:nw
+          { \use:c { @@_map_not_ #4 :Nnn } #1 {#2} {#3} }
+      }
+      {
+        \@@_codepoint_compare:nNnTF {#3} > { "#6 }
+          { \@@_map_class_loop:Nnnnw #1 {#2} {#3} {#4} }
+          {
+            \@@_map_class_end:nw
+              { \use:c { @@_map_ #4 :Nnn } #1 {#2} {#3} }
+          }
+      }
+  }
+\cs_new:Npn \@@_map_class_end:nw #1#2 \q_@@_recursion_stop {#1}
+%    \end{macrocode}
+%   Break before \emph{and} after.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_Control:Nnn #1#2#3
+  {
+    \@@_map_output:Nn #1 {#2}
+    \@@_map_output:Nn #1 {#3}
+    \@@_map_loop:Nnw #1 { }
+  }
+%    \end{macrocode}
+%   Keep collecting.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_Extend:Nnn #1#2#3
+  { \@@_map_loop:Nnw #1 {#2#3} }
+\cs_new_eq:NN \@@_map_SpacingMark:Nnn \@@_map_Extend:Nnn
+%    \end{macrocode}
+%   Outputting anything earlier, the combine with what follows. The only
+%   exclusions are control characters.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_Prepend:Nnn #1#2#3
+  {
+    \@@_map_output:Nn #1 {#2}
+    \@@_map_lookahead:NnNw #1 {#3} \@@_map_Prepend_aux:Nnn
+  }
+\cs_new:Npn \@@_map_Prepend_aux:Nnn #1#2#3
+  {
+    \bool_lazy_or:nnTF
+      { \@@_codepoint_compare_p:nNn {#3} = { "0A } }
+      { \@@_codepoint_compare_p:nNn {#3} = { "0D } }
+      {
+        #1 {#2}
+        \@@_map_loop:Nnw #1 {#3}
+      }
+      {
+        \exp_args:NV \@@_map_Prepend:nNnn
+          \c_@@_grapheme_Control_clist
+          #1 {#2} {#3}
+      }
+  }
+\cs_new:Npn \@@_map_Prepend:nNnn #1#2#3#4
+  {
+    \@@_map_Prepend_loop:Nnnw #2 {#3} {#4}
+      #1 , \q_@@_recursion_tail .. , \q_@@_recursion_stop
+  }
+\cs_new:Npn \@@_map_Prepend_loop:Nnnw #1#2#3 #4 .. #5 ,
+  {
+    \@@_if_q_recursion_tail_stop_do:nn {#4}
+      { \@@_map_loop:Nnw #1 {#2#3} }
+    \@@_codepoint_compare:nNnTF {#3} < { "#4 }
+      {
+        \@@_map_class_end:nw
+          { \@@_map_loop:Nnw #1 {#2#3} }
+      }
+      {
+        \@@_codepoint_compare:nNnTF {#3} > { "#5 }
+          { \@@_map_Prepend_loop:Nnnw #1 {#2} {#3} }
+          {
+            \@@_map_class_end:nw
+              { \@@_map_loop:Nnw #1 {#2} #3 }
+          }
+      }
+  }
+%    \end{macrocode}
+%   Dealing with end-of-class is done such that we can be flexible.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_not_Control:Nnn #1#2#3
+  { \@@_map_class:Nnnn #1 {#2} {#3} { Extend } }
+\cs_new:Npn \@@_map_not_Extend:Nnn #1#2#3
+  { \@@_map_class:Nnnn #1 {#2} {#3} { SpacingMark } }
+\cs_new:Npn \@@_map_not_SpacingMark:Nnn #1#2#3
+  { \@@_map_class:Nnnn #1 {#2} {#3} { Prepend } }
+\cs_new:Npn \@@_map_not_Prepend:Nnn #1#2#3
+  { \@@_map_class:Nnnn #1 {#2} {#3} { L } }
+\cs_new:Npn \@@_map_not_L:Nnn #1#2#3
+  { \@@_map_class:Nnnn #1 {#2} {#3} { LV } }
+\cs_new:Npn \@@_map_not_LV:Nnn #1#2#3
+  { \@@_map_class:Nnnn #1 {#2} {#3} { V } }
+\cs_new:Npn \@@_map_not_V:Nnn #1#2#3
+  { \@@_map_class:Nnnn #1 {#2} {#3} { LVT } }
+\cs_new:Npn \@@_map_not_LVT:Nnn #1#2#3
+  { \@@_map_class:Nnnn #1 {#2} {#3} { T } }
+\cs_new:Npn \@@_map_not_T:Nnn #1#2#3
+  { \@@_map_class:Nnnn #1 {#2} {#3} { Regional_Indicator } }
+\cs_new:Npn \@@_map_not_Regional_Indicator:Nnn #1#2#3
+  {
+    \@@_map_output:Nn #1 {#2}
+    \@@_map_loop:Nnw #1 {#3}
+  }
+%    \end{macrocode}
+%   Hangul needs additional treatment. First we have to deal with
+%   the start-of-Hangul position: output what we had up to now, then
+%   move the the specialist handler. The idea here is to pick off the
+%   different codepoint types one at a time, tracking what else can be
+%   considered at each stage until we hit the end of the viable types.
+%   Other than that, we just keep building up the Hangul codepoints
+%   using a dedicated version of the loop from above.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_L:Nnn #1#2#3
+  {
+    \@@_map_output:Nn #1 {#2}
+    \@@_map_hangul:Nnnw
+      #1 {#3} { L ; V ; LV ; LVT }
+  }
+\cs_new:Npn \@@_map_LV:Nnn #1#2#3
+  {
+    \@@_map_output:Nn #1 {#2}
+    \@@_map_hangul:Nnnw
+      #1 {#3} { V ; T }
+  }
+\cs_new_eq:NN \@@_map_V:Nnn \@@_map_LV:Nnn
+\cs_new:Npn \@@_map_LVT:Nnn #1#2#3
+  {
+    \@@_map_output:Nn #1 {#2}
+    \@@_map_hangul:Nnnw
+      #1 {#3} { T }
+  }
+\cs_new_eq:NN \@@_map_T:Nnn \@@_map_LVT:Nnn
+\cs_new:Npn \@@_map_hangul:Nnnw #1#2#3#4 \q_@@_recursion_stop
+  {
+    \tl_if_head_is_N_type:nTF {#4}
+      { \@@_map_hangul:NnnN #1 {#2} {#3} }
+      {
+        #1 {#2}
+        \@@_map_loop:Nnw #1 { }
+      }
+    #4 \q_@@_recursion_stop
+  }
+\cs_new:Npn \@@_map_hangul:NnnN #1#2#3#4
+  {
+    \@@_if_q_recursion_tail_stop_do:Nn #4
+      {
+        #1 {#2}
+        \text_map_break:
+      }
+    \token_if_cs:NTF #4
+      {
+        #1 {#2}
+        \@@_map_loop:Nnw #1 { }
+      }
+      {
+        \@@_codepoint_process:nN
+          { \@@_map_hangul:Nnnn #1 {#2} {#3} } #4
+      }
+  }
+\cs_new:Npn \@@_map_hangul:Nnnn #1#2#3#4
+  {
+    \@@_map_hangul_aux:Nnnw #1 {#2} {#4}
+      #3 ; \q_recursion_tail ; \q_recursion_stop
+  }
+\cs_new:Npn \@@_map_hangul_aux:Nnnw #1#2#3#4 ;
+  {
+    \quark_if_recursion_tail_stop_do:nn {#4}
+      { \@@_map_loop:Nnw #1 {#2} #3 }
+    \exp_args:Nv \@@_map_hangul:nNnnnw { c_@@_grapheme_ #4 _clist }
+      #1 {#2} {#3} {#4}
+  }
+\cs_new:Npn \@@_map_hangul:nNnnnw #1#2#3#4#5#6  \q_recursion_stop
+  {
+    \@@_map_hangul_loop:Nnnnnw #2 {#3} {#4} {#5} {#6}
+      #1 , \q_@@_recursion_tail .. , \q_@@_recursion_stop
+  }
+\cs_new:Npn \@@_map_hangul_loop:Nnnnnw #1#2#3#4#5 #6 .. #7 ,
+  {
+    \@@_if_q_recursion_tail_stop_do:nn {#6}
+      { \@@_map_hangul_next:Nnnn #1 {#2} {#3} {#5} }
+    \@@_codepoint_compare:nNnTF {#3} < { "#6 }
+      {
+        \@@_map_hangul_end:nw
+          { \@@_map_hangul_next:Nnnn #1 {#2} {#3} {#5} }
+      }
+      {
+        \@@_codepoint_compare:nNnTF {#3} > { "#7 }
+          { \@@_map_hangul_loop:Nnnnnw #1 {#2} {#3} {#4} {#5} }
+          {
+            \@@_map_hangul_end:nw
+              { \use:c { @@_map_hangul_ #4 :Nnn } #1 {#2} {#3} }
+          }
+      }
+  }
+\cs_new:Npn \@@_map_hangul_next:Nnnn #1#2#3#4
+  { \@@_map_hangul_aux:Nnnw #1 {#2} {#3} #4 \q_recursion_stop }
+\cs_new:Npn \@@_map_hangul_end:nw #1#2 \q_@@_recursion_stop {#1}
+\cs_new:Npn \@@_map_hangul_L:Nnn #1#2#3
+  {
+    \@@_map_hangul:Nnnw
+      #1 {#2#3} { L V { LV } { LVT } }
+  }
+\cs_new:Npn \@@_map_hangul_LV:Nnn #1#2#3
+  {
+    \@@_map_hangul:Nnnw
+      #1 {#2#3} { VT }
+  }
+\cs_new_eq:NN \@@_map_hangul_V:Nnn \@@_map_hangul_LV:Nnn
+\cs_new:Npn \@@_map_hangul_LVT:Nnn #1#2#3
+  {
+    \@@_map_hangul:Nnnw
+      #1 {#2#3} { T }
+  }
+\cs_new_eq:NN \@@_map_hangul_T:Nnn \@@_map_hangul_LVT:Nnn
+%    \end{macrocode}
+%  The Regional Indicator rule means looking ahead and dealing with the
+%  case where there are two in a row. So we use a look ahead to pick them
+%  off. As there is only one range the values are hard-coded.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_Regional_Indicator:Nnn #1#2#3
+  {
+    \@@_map_output:Nn #1 {#2}
+    \@@_map_lookahead:NnNw #1 {#3} \@@_map_Regional_Indicator_aux:Nnn
+  }
+\cs_new:Npn \@@_map_Regional_Indicator_aux:Nnn #1#2#3
+  {
+    \bool_lazy_or:nnTF
+      { \@@_codepoint_compare_p:nNn {#3} < { "1F1E6 } }
+      { \@@_codepoint_compare_p:nNn {#3} > { "1F1FF } }
+      {
+        \@@_map_loop:Nnw #1 {#2} #3
+      }
+      { \@@_map_loop:Nnw #1 {#2#3} }
+  }
+%    \end{macrocode}
+%   A generic loop-ahead setup.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_lookahead:NnNw #1#2#3#4 \q_@@_recursion_stop
+  {
+    \tl_if_head_is_N_type:nTF {#4}
+      { \@@_map_lookahead:NnNN #1 {#2} #3 }
+      { \@@_map_loop:Nnw #1 {#2} }
+    #4 \q_@@_recursion_stop
+  }
+\cs_new:Npn \@@_map_lookahead:NnNN #1#2#3#4
+  {
+    \@@_if_q_recursion_tail_stop_do:Nn #4 { #1 {#2} }
+    \token_if_cs:NTF #4
+      {
+        #1 {#2}
+        \@@_map_loop:Nnw #1 { }
+      }
+      { \@@_codepoint_process:nN { #3 #1 {#2} } }
+        #4
+  }
+%    \end{macrocode}
+%   For the end of the process.
+%    \begin{macrocode}
+\cs_new:Npn \@@_map_output:Nn #1#2
+  { \tl_if_blank:nF {#2} { #1 {#2} } }
+\cs_new:Npn \text_map_break:
+  { \prg_map_break:Nn \text_map_break: { } }
+\cs_new:Npn \text_map_break:n
+  { \prg_map_break:Nn \text_map_break: }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\text_map_inline:nn}
+%   The standard non-expandable inline version.
+%    \begin{macrocode}
+\cs_new_protected:Npn \text_map_inline:nn #1#2
+  {
+    \int_gincr:N \g__kernel_prg_map_int
+    \cs_gset_protected:cpn
+      { @@_map_ \int_use:N \g__kernel_prg_map_int :w } ##1 {#2}
+    \exp_args:Nnc \text_map_function:nN {#1}
+      { @@_map_ \int_use:N \g__kernel_prg_map_int :w }
+    \prg_break_point:Nn \text_map_break:
+      { \int_gdecr:N \g__kernel_prg_map_int }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macrocode}
+%</package>
+%    \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex


Property changes on: trunk/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3text.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3text.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3text.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %
@@ -184,6 +184,8 @@
 %       combining dot is removed when uppercasing in these cases. Note that
 %       \emph{only} the accents used in Lithuanian are covered: the behaviour
 %       of other accents are not modified.
+%     \item Medieval Latin (\texttt{la-xmedieval}).
+%      The characters |u| and |V| are interchanged on case changing.
 %     \item Dutch (\texttt{nl}).
 %       Capitalisation of \texttt{ij} at the beginning of titlecased
 %       input produces \texttt{IJ} rather than \texttt{Ij}. The output
@@ -299,6 +301,62 @@
 %   \texttt{true}.
 % \end{variable}
 %
+% \section{Mapping to graphemes}
+%
+% Grapheme splitting is implemented using the algorithm described in Unicode
+% Standard Annex \#29. This includes support for extended grapheme clusters.
+% Text starting with a line feed or carriage return character will drop this
+% due to standard \TeX{} processing. At present extended pictograms are
+% not supported: these may be added in a future release.
+%
+% \begin{function}[rEXP, added = 2022-08-04]{\text_map_function:nN}
+%   \begin{syntax}
+%     \cs{text_map_function:nN} \meta{text} \Arg{function}
+%   \end{syntax}
+%   Takes user input \meta{text} and expands as described for
+%   \cs{text_expand:n}, then maps over the \emph{graphemes} within the
+%   result, passing each grapheme to the \meta{function}.
+%   Broadly a grapheme is a \enquote{user perceived character}:
+%   the Unicode Consortium describe the decomposition of input to
+%   graphemes in depth, and the approach used here implements that
+%   algorithm. The \meta{function} should accept one argument as \meta{balanced
+%   text}: this may be comprise codepoints or may be a control sequence.
+%   With $8$-bit engines, the codepoint(s) themselves may of course be
+%   made up of multiple bytes: the mapping will pass the correct codepoints
+%   independent of the engine in use.
+%   See also \cs{text_map_inline:nn}.
+% \end{function}
+%
+% \begin{function}[added = 2022-08-04]{\text_map_inline:nn}
+%   \begin{syntax}
+%     \cs{text_map_inline:nn} \meta{text} \Arg{inline function}
+%   \end{syntax}
+%   Takes user input \meta{text} and expands as described for
+%   \cs{text_expand:n}, then maps over the \emph{graphemes} within the
+%   result, passing each grapheme to the \meta{inline function}.
+%   Broadly a grapheme is a \enquote{user perceived character}:
+%   the Unicode Consortium describe the decomposition of input to
+%   graphemes in depth, and the approach used here implements that
+%   algorithm. The \meta{inline function} should consist of code which
+%   receives the grapheme as \meta{balanced
+%   text}: this may be comprise codepoints or may be a control sequence.
+%   With $8$-bit engines, the codepoint(s) themselves may of course be
+%   made up of multiple bytes: the mapping will pass the correct codepoints
+%   independent of the engine in use.
+%   See also \cs{text_map_function:nN}.
+% \end{function}
+%
+% \begin{function}[rEXP, added = 2022-08-04]
+%   {\text_map_break:, \text_map_break:n}
+%   \begin{syntax}
+%     \cs{text_map_break:}
+%     \cs{text_map_break:n} \Arg{code}
+%   \end{syntax}
+%   Used to terminate a \cs[no-index]{text_map_\ldots} function before all
+%   entries in the \meta{text} have been processed. This
+%   normally takes place within a conditional statement.
+% \end{function}
+%
 % \end{documentation}
 %
 % \begin{implementation}
@@ -357,11 +415,14 @@
 % \end{macro}
 %
 % \begin{macro}[EXP]{\@@_if_q_recursion_tail_stop_do:Nn}
+% \begin{macro}[EXP]{\@@_if_q_recursion_tail_stop_do:nn}
 %   Functions to query recursion quarks.
 %    \begin{macrocode}
 \__kernel_quark_new_test:N \@@_if_q_recursion_tail_stop_do:Nn
+\__kernel_quark_new_test:N \@@_if_q_recursion_tail_stop_do:nn
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
 %
 % \begin{variable}{\s_@@_recursion_tail,\s_@@_recursion_stop}
 %   Internal scan marks quarks.
@@ -581,6 +642,121 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \subsection{Codepoint utilities}
+%
+% For working with codepoints in an engine-neutral way.
+%
+% \begin{macro}[EXP]{\@@_codepoint_process:nN}
+% \begin{macro}[EXP]{\@@_codepoint_process:nNN}
+% \begin{macro}[EXP]{\@@_codepoint_process:nNNN}
+% \begin{macro}[EXP]{\@@_codepoint_process:nNNNN}
+%   Grab a codepoint and apply some code to it: here |#1| should expect one
+%   following \emph{balanced text}.
+%    \begin{macrocode}
+\bool_lazy_or:nnTF
+  { \sys_if_engine_luatex_p: }
+  { \sys_if_engine_xetex_p: }
+  {
+    \cs_new:Npn \@@_codepoint_process:nN #1#2 { #1 {#2} }
+  }
+  {
+    \cs_new:Npn \@@_codepoint_process:nN #1#2
+      {
+        \int_compare:nNnTF { `#2 } > { "80 }
+          {
+            \int_compare:nNnTF { `#2 } < { "E0 }
+              { \@@_codepoint_process:nNN }
+              {
+                 \int_compare:nNnTF { `#2 } < { "F0 }
+                   { \@@_codepoint_process:nNNN }
+                   { \@@_codepoint_process:nNNNN }
+              }
+          }
+          { \use:n }
+            {#1} #2
+      }
+    \cs_new:Npn \@@_codepoint_process:nNN #1#2#3
+      { #1 {#2#3} }
+    \cs_new:Npn \@@_codepoint_process:nNNN #1#2#3#4
+      { #1 {#2#3#4} }
+    \cs_new:Npn \@@_codepoint_process:nNNNN #1#2#3#4#5
+      { #1 {#2#3#4#5} }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP, pTF]{\@@_codepoint_compare:nNn}
+% \begin{macro}[EXP]{\@@_codepoint_compare:N, \@@_codepoint_compare_aux:N}
+% \begin{macro}[EXP]{\@@_codepoint_compare:NN}
+% \begin{macro}[EXP]{\@@_codepoint_compare:NNN}
+% \begin{macro}[EXP]{\@@_codepoint_compare:NNNN}
+%   Allows comparison for all engines using a first \enquote{character} followed
+%   by a codepoint.
+%    \begin{macrocode}
+\bool_lazy_or:nnTF
+  { \sys_if_engine_luatex_p: }
+  { \sys_if_engine_xetex_p: }
+  {
+    \prg_new_conditional:Npnn
+      \@@_codepoint_compare:nNn #1#2#3 { TF , p }
+      {
+        \int_compare:nNnTF { `#1 } #2 {#3}
+          \prg_return_true: \prg_return_false:
+      }
+  }
+  {
+    \prg_new_conditional:Npnn
+      \@@_codepoint_compare:nNn #1#2#3 { TF , p }
+      {
+        \int_compare:nNnTF { \@@_codepoint_compare:N #1 }
+            #2 {#3}
+          \prg_return_true: \prg_return_false:
+      }
+    \cs_new:Npn \@@_codepoint_compare:N #1
+      {
+        \if_int_compare:w `#1 > "80 \exp_stop_f:
+          \if_int_compare:w `#1 < "E0 \exp_stop_f:
+            \exp_after:wN \exp_after:wN \exp_after:wN
+              \@@_codepoint_compare:NN
+          \else:
+            \if_int_compare:w `#1 < "F0 \exp_stop_f:
+              \exp_after:wN \exp_after:wN \exp_after:wN
+              \exp_after:wN \exp_after:wN \exp_after:wN
+              \exp_after:wN \@@_codepoint_compare:NNN
+            \else:
+              \exp_after:wN \exp_after:wN \exp_after:wN
+              \exp_after:wN \exp_after:wN \exp_after:wN
+              \exp_after:wN \@@_codepoint_compare:NNNN
+            \fi:
+          \fi:
+        \else:
+          \exp_after:wN \@@_codepoint_compare_aux:N
+        \fi:
+          #1
+      }
+    \cs_new:Npn \@@_codepoint_compare_aux:N #1 { `#1 }
+    \cs_new:Npn \@@_codepoint_compare:NN #1#2
+      { (`#1 - "C0) * "40 + `#2 - "80 }
+    \cs_new:Npn \@@_codepoint_compare:NNN #1#2#3
+      { (`#1 - "E0) * "1000 + (`#2 - "80) * "40 + `#3 - "80 }
+    \cs_new:Npn \@@_codepoint_compare:NNNN #1#2#3#4
+      {
+          (`#1 - "F0) * "40000 
+        + (`#2 - "80) * "1000
+        + (`#3 - "80) * "40
+        + `#4 - "80
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
 % \subsection{Configuration variables}
 %
 % \begin{variable}{\l_text_accents_tl, \l_text_letterlike_tl}

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -44,7 +44,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3token.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %
@@ -1795,36 +1795,113 @@
 % \end{macro}
 %
 % \begin{macro}[rEXP]{\char_to_nfd:N}
-% \begin{macro}[rEXP]{\@@_to_nfd:n}
+% \begin{macro}[rEXP]{\@@_to_nfd:n, \@@_to_nfd:e}
 % \begin{macro}[rEXP]{\@@_to_nfd:Nw}
-%   Look up any \textsc{nfd} and recursively produce the result.
+% \begin{macro}[rEXP]{\char_to_nfd:n}
+% \begin{macro}[rEXP]{\char_to_nfd:w}
+% \begin{macro}[rEXP]{\char_nfd_generate:n}
+% \begin{macro}[rEXP]{\char_nfd_generate:nnnn}
+%   Look up any \textsc{nfd} and recursively produce the result. Having shared
+%   code between Unicode and $8$-bit engines would be ideal, but this would be
+%   awkward as we have completely different treatment of catcodes, numbers
+%   of tokens, etc. The apparent saving becomes more of a headache than it's
+%   worth \dots
 %    \begin{macrocode}
-\cs_new:Npn \char_to_nfd:N #1
+\bool_lazy_or:nnTF
+  { \sys_if_engine_luatex_p: }
+  { \sys_if_engine_xetex_p: }
   {
-    \cs_if_exist:cTF { c_@@_nfd_ \token_to_str:N #1 _ tl }
+    \cs_new:Npn \char_to_nfd:N #1
       {
-        \exp_after:wN \exp_after:wN \exp_after:wN \@@_to_nfd:Nw
-          \exp_after:wN \exp_after:wN \exp_after:wN #1
-            \cs:w c_@@_nfd_ \token_to_str:N #1 _ tl \cs_end:
-              \s_@@_stop
+        \cs_if_exist:cTF { c_@@_nfd_ \token_to_str:N #1 _ tl }
+          {
+            \exp_after:wN \exp_after:wN \exp_after:wN \@@_to_nfd:Nw
+              \exp_after:wN \exp_after:wN \exp_after:wN #1
+                \cs:w c_@@_nfd_ \token_to_str:N #1 _tl \cs_end:
+                  \s_@@_stop
+          }
+          { \exp_not:n {#1} }
       }
-      { \exp_not:n {#1} }
+    \cs_new_eq:NN \@@_to_nfd:n \char_to_nfd:N
+    \cs_generate_variant:Nn \@@_to_nfd:n { e }
+    \cs_new:Npn \@@_to_nfd:Nw #1#2#3 \s_@@_stop
+      {
+        \@@_to_nfd:e
+          { \char_generate:nn { `#2 } { \@@_change_case_catcode:N #1 } }
+        \tl_if_blank:nF {#3}
+          {
+            \@@_to_nfd:e
+               { \char_generate:nn { `#3 } { \char_value_catcode:n { `#3 } } }
+          }
+      }
+    \cs_new:Npn \char_to_nfd:n #1
+      {
+        \@@_to_nfd:e { \char_generate:nn {#1} { \char_value_catcode:n {#1} } }
+      }
   }
-\cs_set_eq:NN \@@_to_nfd:n \char_to_nfd:N
-\cs_new:Npn \@@_to_nfd:Nw #1#2#3 \s_@@_stop
   {
-    \exp_args:Ne \@@_to_nfd:n
-      { \char_generate:nn { `#2 } { \@@_change_case_catcode:N #1 } }
-    \tl_if_blank:nF {#3}
+    \cs_new:Npn \char_to_nfd:N #1 { \exp_not:n {#1} }
+    \cs_new:Npn \char_to_nfd:n #1
       {
-        \exp_args:Ne \@@_to_nfd:n
-          { \char_generate:nn { `#3 } { \char_value_catcode:n { `#3 } } }
+        \int_compare:nNnTF {#1} > { "80 }
+          { \exp_args:Ne \@@_to_nfd:n { \@@_nfd_generate:n {#1} } }
+          { \@@_nfd_generate:n {#1} }
       }
+    \cs_new:Npn \@@_to_nfd:n #1
+      {
+        \cs_if_exist:cTF { c_@@_nfd_ \tl_to_str:n {#1} _ tl }
+          {
+            \exp_after:wN \exp_after:wN \exp_after:wN \@@_to_nfd:w
+              \cs:w c_@@_nfd_ \tl_to_str:n {#1} _tl \cs_end:
+                \s_@@_stop
+          }
+          { \exp_not:n {#1} }
+      }
+    \cs_new:Npn \@@_to_nfd:w #1#2 \s_@@_stop
+      {
+        \@@_to_nfd:n {#1}
+        \tl_if_blank:nF {#2}
+          { \@@_to_nfd:n {#2} }
+      }
+     \cs_new:Npn \@@_nfd_generate:n #1
+       {
+         \use:e
+           {
+             \exp_not:N \@@_nfd_generate:nnnn
+               \char_to_utfviii_bytes:n {#1}
+           }
+       }
+      \cs_new:Npn \@@_nfd_generate:nnnn #1#2#3#4
+        {
+          \tl_if_blank:nTF {#2}
+            { \char_generate:nn {#1} { \char_value_catcode:n {#1} } }
+            {
+              \exp_after:wN \exp_after:wN \exp_after:wN
+                \exp_not:N \char_generate:nn {#1} { 13 }
+              \exp_after:wN \exp_after:wN \exp_after:wN
+                \exp_not:N \char_generate:nn {#2} { 13 }
+              \tl_if_blank:nF {#3}
+                {
+                  \exp_after:wN \exp_after:wN \exp_after:wN
+                    \exp_not:N \char_generate:nn {#3} { 13 }
+                  \tl_if_blank:nF {#4}
+                    {
+                      \exp_after:wN \exp_after:wN \exp_after:wN
+                        \exp_not:N \char_generate:nn {#4} { 13 }
+                    }
+                }
+            }
+           
+        }
   }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
 % \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
 %
 % \begin{macro}[EXP]
 %   {

Modified: trunk/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -43,7 +43,7 @@
 %    }^^A
 % }
 %
-% \date{Released 2022-08-23}
+% \date{Released 2022-08-30}
 %
 % \maketitle
 %
@@ -67,10 +67,9 @@
 %<@@=char>
 %    \end{macrocode}
 %
-% Case changing both for strings and \enquote{text} requires data from
-% the Unicode Consortium. Some of this is build in to the format (as
-% \tn{lccode} and \tn{uccode} values) but this covers only the simple
-% one-to-one situations and does not fully handle for example case folding.
+% Text operations requires data from the Unicode Consortium. Data read into
+% Unicode engine formats is at best a small part of what we need, so there
+% is a loader here to set  up the appropriate data structures.
 %
 % As only the data needs to remain at the end of this process, everything
 % is set up inside a group. The only thing that is outside is creating a
@@ -78,30 +77,67 @@
 % all engines. For performance reasons, some of the code here is very
 % low-level: the material is read during loading \pkg{expl3} in package
 % mode.
+%
+% Parsing the data files can be the same way for all engines, but the detail
+% of data storage varies depending on whether they are Unicode or $8$-bit
+% internally.Parsing is therefore done by common functions, with the data
+% storage usign engine-specific auxiliaries.
+%
+% Conversion of a codepoint to a character (Unicode engines) or to one
+% or more bytes ($8$-bit engines) is required. We might need those to be
+% detokenized: if not, for Unicode engines they have the current category
+% code.
 %    \begin{macrocode}
 \ior_new:N \g_@@_data_ior
-\bool_lazy_or:nnTF { \sys_if_engine_luatex_p: } { \sys_if_engine_xetex_p: }
-  {
-    \group_begin:
-%    \end{macrocode}
-%   Access the primitive but suppress further expansion: active chars are
-%   otherwise an issue.
-%    \begin{macrocode}
-      \cs_set:Npn \@@_generate_char:n #1
-        { \tex_detokenize:D \tex_expandafter:D { \tex_Uchar:D " #1 } }
-%    \end{macrocode}
-%   A fast local implementation for generating characters; the chars may
-%   be active, so we prevent further expansion.
-%    \begin{macrocode}
-      \cs_set:Npx \@@_generate:n #1
+\group_begin:
+  \bool_lazy_or:nnTF
+    { \sys_if_engine_luatex_p: }
+    { \sys_if_engine_xetex_p: }
+    {
+      \cs_set:Npn \@@_generate_other:n #1
+        { \tex_detokenize:D \tex_expandafter:D { \tex_Uchar:D #1 } }
+      \cs_set:Npn \@@_generate:n #1
         {
-          \exp_not:N \tex_unexpanded:D \exp_not:N \exp_after:wN
+          \tex_unexpanded:D \exp_after:wN
+            { \tex_Ucharcat:D #1 ~ \tex_catcode:D #1 ~ }
+        } 
+    }
+    {
+      \cs_set:Npn \@@_generate_other:n #1
+        {
+          \tex_detokenize:D \tex_expandafter:D
+            { \tex_expanded:D { \@@_generate:n {#1} } }
+        }
+      \cs_set:Npn \@@_generate:n #1
+        {
+          \use:e
             {
-              \exp_not:N \tex_Ucharcat:D
-                #1 ~
-                \tex_catcode:D #1 ~
+              \exp_not:N \@@_generate:nnnn
+                \char_to_utfviii_bytes:n {#1}
             }
-        } 
+        }
+      \cs_set:Npn \@@_generate:nnnn #1#2#3#4
+        {
+          \tex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN
+            { \char_generate:nn {#1} { 13 } }
+          \tl_if_blank:nF {#2}
+            {
+              \tex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN
+                { \char_generate:nn {#2} { 13 } }
+              \tl_if_blank:nF {#3}
+                {
+                  \tex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN
+                    { \char_generate:nn {#3} { 13 } }
+                  \tl_if_blank:nF {#4}
+                    {
+                      \tex_unexpanded:D
+                        \exp_after:wN \exp_after:wN \exp_after:wN
+                          { \char_generate:nn {#4} { 13 } }
+                    }
+                }
+            }
+        }
+    }
 %    \end{macrocode}
 % Parse the main Unicode data file for two things. First, we want the titlecase
 % exceptions: the one-to-one lower- and uppercase mappings it contains are all
@@ -109,51 +145,52 @@
 % just the canonical \textsc{nfd} mappings. Those all yield either one or two
 % codepoints, so the split is relatively easy.
 %    \begin{macrocode}
-      \ior_open:Nn \g_@@_data_ior { UnicodeData.txt }
-      \cs_set_protected:Npn \@@_data_auxi:w
-        #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ; #8 ; #9 ;
+  \cs_set_protected:Npn \@@_data_auxi:w
+    #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ; #8 ; #9 ;
+    {
+      \tl_if_blank:nF {#6}
         {
-          \tl_if_blank:nF {#6}
-            {
-              \tl_if_head_eq_charcode:nNF {#6}  < % >
-                { \@@_data_auxii:w #1 ; #6 ~ \q_stop }
-            }
-          \@@_data_auxiii:w #1 ;
+          \tl_if_head_eq_charcode:nNF {#6}  < % >
+            { \@@_data_auxii:w #1 ; #6 ~ \q_stop }
         }
-      \cs_set_protected:Npn \@@_data_auxii:w #1 ; #2 ~ #3 \q_stop
+      \@@_data_auxiii:w #1 ;
+    }
+  \cs_set_protected:Npn \@@_data_auxii:w #1 ; #2 ~ #3 \q_stop
+    {
+      \tl_const:cx
+        { c_@@_nfd_ \@@_generate_other:n { "#1 } _tl }
         {
-          \tl_const:cx
-            { c_@@_nfd_ \@@_generate_char:n {#1} _tl }
-            {
-              \@@_generate:n { "#2 }
-              \tl_if_blank:nF {#3}
-                { \@@_generate:n { "#3 } }
+          { \@@_generate:n { "#2 } }
+          {
+            \tl_if_blank:nF {#3}
+              { \@@_generate:n { "#3 } }
             }
         }
-      \cs_set_protected:Npn \@@_data_auxiii:w
-        #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ~ \q_stop
-        {
-          \cs_set_nopar:Npn \l_@@_tmpa_tl {#7}
-          \reverse_if:N \if_meaning:w \l_@@_tmpa_tl \c_empty_tl
-            \cs_set_nopar:Npn \l_@@_tmpb_tl {#5}
-            \reverse_if:N \if_meaning:w \l_@@_tmpa_tl \l_@@_tmpb_tl
-              \tl_const:cx
-                { c_@@_titlecase_ \@@_generate_char:n {#1} _tl }
-                { \@@_generate:n { "#7 } }
-            \fi:
-          \fi:
-        }
-      \group_begin:
-        \char_set_catcode_space:n { `\  }%
-        \ior_map_variable:NNn \g_@@_data_ior \l_@@_tmpa_tl
-          {%
-            \if_meaning:w \l_@@_tmpa_tl \c_space_tl
-              \exp_after:wN \ior_map_break:
-            \fi:
-            \exp_after:wN \@@_data_auxi:w \l_@@_tmpa_tl \q_stop
-          }%
-      \group_end:
-      \ior_close:N \g_@@_data_ior
+    }
+  \cs_set_protected:Npn \@@_data_auxiii:w
+    #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ~ \q_stop
+    {
+      \cs_set_nopar:Npn \l_@@_tmpa_tl {#7}
+      \reverse_if:N \if_meaning:w \l_@@_tmpa_tl \c_empty_tl
+        \cs_set_nopar:Npn \l_@@_tmpb_tl {#5}
+        \reverse_if:N \if_meaning:w \l_@@_tmpa_tl \l_@@_tmpb_tl
+          \tl_const:cx
+            { c_@@_titlecase_ \@@_generate_other:n { "#1 } _tl }
+            { \@@_generate:n { "#7 } }
+        \fi:
+      \fi:
+    }
+  \ior_open:Nn \g_@@_data_ior { UnicodeData.txt }
+  \group_begin:
+    \char_set_catcode_space:n { `\  }%
+    \ior_map_variable:NNn \g_@@_data_ior \l_@@_tmpa_tl
+      {%
+        \if_meaning:w \l_@@_tmpa_tl \c_space_tl
+          \exp_after:wN \ior_map_break:
+        \fi:
+        \exp_after:wN \@@_data_auxi:w \l_@@_tmpa_tl \q_stop
+      }%
+  \group_end:
 %    \end{macrocode}
 % The other data files all use C-style comments so we have to worry about
 % |#| tokens (and reading as strings). The set up for case folding is in two
@@ -162,94 +199,141 @@
 % always store the result, splitting up the two or three code points in the input
 % as required.
 %    \begin{macrocode}
-      \ior_open:Nn \g_@@_data_ior { CaseFolding.txt }
+  \ior_open:Nn \g_@@_data_ior { CaseFolding.txt }
+  \cs_set_protected:Npn \@@_data_auxi:w #1 ;~ #2 ;~ #3 ; #4 \q_stop
+    {
+      \if:w \tl_head:n { #2 ? } C
+        \reverse_if:N \if_int_compare:w
+          \char_value_lccode:n {"#1} = "#3 ~
+          \tl_const:cx
+            { c_@@_foldcase_ \@@_generate_other:n { "#1 } _tl }
+            { \@@_generate:n { "#3 } }
+        \fi:
+      \else:
+        \if:w \tl_head:n { #2 ? } F
+          \@@_data_auxii:w #1 ~ #3 ~ \q_stop
+        \fi:
+      \fi:
+    }
+  \bool_lazy_or:nnF
+    { \sys_if_engine_luatex_p: }
+    { \sys_if_engine_xetex_p: }
+    {
       \cs_set_protected:Npn \@@_data_auxi:w #1 ;~ #2 ;~ #3 ; #4 \q_stop
         {
-          \if:w \tl_head:n { #2 ? } C
-            \reverse_if:N \if_int_compare:w
-              \char_value_lccode:n {"#1} = "#3 ~
-              \tl_const:cx
-                { c_@@_foldcase_ \@@_generate_char:n {#1} _tl }
-                { \@@_generate:n { "#3 } }
-            \fi:
-          \else:
-            \if:w \tl_head:n { #2 ? } F
-              \@@_data_auxii:w #1 ~ #3 ~ \q_stop
-            \fi:
+          \if:w \tl_head:n { #2 ? } F
+            \@@_data_auxii:w #1 ~ #3 ~ \q_stop
           \fi:
         }
-      \cs_set_protected:Npn \@@_data_auxii:w #1 ~ #2 ~ #3 ~ #4 \q_stop
+    }
+  \cs_set_protected:Npn \@@_data_auxii:w #1 ~ #2 ~ #3 ~ #4 \q_stop
+    {
+      \tl_const:cx { c_@@_foldcase_ \@@_generate_other:n { "#1 } _tl }
         {
-          \tl_const:cx { c_@@_foldcase_ \@@_generate_char:n {#1} _tl }
+          \@@_generate:n { "#2 }
+          \@@_generate:n { "#3 }
+          \tl_if_blank:nF {#4}
+            { \@@_generate:n { \int_value:w "#4 } }
+        }
+    }
+  \ior_str_map_inline:Nn \g_@@_data_ior
+    {
+      \reverse_if:N \if:w \c_hash_str \tl_head:w #1 \c_hash_str \q_stop
+        \@@_data_auxi:w #1 \q_stop
+      \fi:
+    }
+  \ior_close:N \g_@@_data_ior
+%    \end{macrocode}
+% For upper- and lowercasing special situations, there is a bit more to
+% do as we also have title casing to consider, plus we need to stop part-way
+% through the file.
+%    \begin{macrocode}
+  \ior_open:Nn \g_@@_data_ior { SpecialCasing.txt }
+  \cs_set_protected:Npn \@@_data_auxi:w
+    #1 ;~ #2 ;~ #3 ;~ #4 ; #5 \q_stop
+    {
+      \use:n { \@@_data_auxii:w #1 ~ lower ~ #2 ~ } ~ \q_stop
+      \use:n { \@@_data_auxii:w #1 ~ upper ~ #4 ~ } ~ \q_stop
+      \str_if_eq:nnF {#3} {#4}
+        { \use:n { \@@_data_auxii:w #1 ~ title ~ #3 ~ } ~ \q_stop }
+    }
+  \cs_set_protected:Npn \@@_data_auxii:w
+    #1 ~ #2 ~ #3 ~ #4 ~ #5 \q_stop
+    {
+      \tl_if_empty:nF {#4}
+        {
+          \tl_const:cx { c_@@_ #2 case_ \@@_generate_other:n { "#1 } _tl }
             {
-              \@@_generate:n { "#2 }
               \@@_generate:n { "#3 }
-              \tl_if_blank:nF {#4}
-                { \@@_generate:n { \int_value:w "#4 } }
+              \@@_generate:n { "#4 }
+              \tl_if_blank:nF {#5}
+                { \@@_generate:n { "#5 } }
             }
         }
-      \ior_str_map_inline:Nn \g_@@_data_ior
+    }
+  \ior_str_map_inline:Nn \g_@@_data_ior
+    {
+      \str_if_eq:eeTF { \tl_head:w #1 \c_hash_str \q_stop } { \c_hash_str }
         {
-          \reverse_if:N \if:w \c_hash_str \tl_head:w #1 \c_hash_str \q_stop
-            \@@_data_auxi:w #1 \q_stop
-          \fi:
+          \str_if_eq:eeT
+            {#1}
+            { \c_hash_str \c_space_tl Conditional~Mappings }
+            { \ior_map_break: }
         }
-      \ior_close:N \g_@@_data_ior
+        { \@@_data_auxi:w #1 \q_stop }
+    }
+  \ior_close:N \g_@@_data_ior
+\group_end:
+
 %    \end{macrocode}
-% For upper- and lowercasing special situations, there is a bit more to
-% do as we also have title casing to consider, plus we need to stop part-way
-% through the file.
+%
 %    \begin{macrocode}
-      \ior_open:Nn \g_@@_data_ior { SpecialCasing.txt }
-      \cs_set_protected:Npn \@@_data_auxi:w
-        #1 ;~ #2 ;~ #3 ;~ #4 ; #5 \q_stop
+%<@@=text>
+%    \end{macrocode}
+%
+%  Read the Unicode grapheme data. This is quite easy to handle and we only need
+%  codepoints, not characters, so there is no need to worry about the engine in use.
+%  As reading as a string is most convenient, we have to do some work to remove
+%  spaces: the hardest part of the entire process!
+%    \begin{macrocode}
+\ior_new:N \g_@@_data_ior
+\group_begin:
+  \ior_open:Nn \g_@@_data_ior { GraphemeBreakProperty.txt }
+  \cs_set_nopar:Npn \l_@@_tmpa_str { }
+  \cs_set_nopar:Npn \l_@@_tmpb_str { }
+  \cs_set_protected:Npn \@@_data_auxi:w #1 ;~ #2 ~ #3 \q_stop
+    {
+      \str_if_eq:VnF \l_@@_tmpb_str {#2}
         {
-          \use:n { \@@_data_auxii:w #1 ~ lower ~ #2 ~ } ~ \q_stop
-          \use:n { \@@_data_auxii:w #1 ~ upper ~ #4 ~ } ~ \q_stop
-          \str_if_eq:nnF {#3} {#4}
-            { \use:n { \@@_data_auxii:w #1 ~ title ~ #3 ~ } ~ \q_stop }
-        }
-      \cs_set_protected:Npn \@@_data_auxii:w
-        #1 ~ #2 ~ #3 ~ #4 ~ #5 \q_stop
-        {
-          \tl_if_empty:nF {#4}
+          \str_if_empty:NF \l_@@_tmpb_str
             {
-              \tl_const:cx { c_@@_ #2 case_ \@@_generate_char:n {#1} _tl }
-                {
-                  \@@_generate:n { "#3 }
-                  \@@_generate:n { "#4 }
-                  \tl_if_blank:nF {#5}
-                    { \@@_generate:n { "#5 } }
-                }
+              \clist_const:cx { c_@@_grapheme_ \l_@@_tmpb_str _clist }
+                { \exp_after:wN \use_none:n \l_@@_tmpa_str }
+              \cs_set_nopar:Npn \l_@@_tmpa_str { }
             }
+          \cs_set_nopar:Npn \l_@@_tmpb_str {#2}
         }
-      \ior_str_map_inline:Nn \g_@@_data_ior
+      \@@_data_auxii:w #1 .. #1 .. #1 \q_stop
+    }
+  \cs_set_protected:Npn \@@_data_auxii:w #1 .. #2 .. #3 \q_stop
+    {
+      \cs_set_nopar:Npx \l_@@_tmpa_str
         {
-          \str_if_eq:eeTF
-            { \tl_head:w #1 \c_hash_str \q_stop }
-            { \c_hash_str }
-            {
-              \str_if_eq:eeT
-                {#1}
-                { \c_hash_str \c_space_tl Conditional~Mappings }
-                { \ior_map_break: }
-            }
+          \l_@@_tmpa_str ,
+          \tl_trim_spaces:n {#1} .. \tl_trim_spaces:n {#2}
+        }
+    }
+  \ior_str_map_inline:Nn \g_@@_data_ior
+    {
+      \str_if_eq:eeF { \tl_head:w #1 \c_hash_str \q_stop } { \c_hash_str }
+        {
+          \tl_if_blank:nF {#1}
             { \@@_data_auxi:w #1 \q_stop }
         }
-      \ior_close:N \g_@@_data_ior
-    \group_end:
-  }
+    }
+  \ior_close:N \g_@@_data_ior
+\group_end:    
 %    \end{macrocode}
-% For the $8$-bit engines, open the stream and close again: this keeps
-% file records the same.
-%    \begin{macrocode}
-  {
-    \group_begin:
-      \ior_open:Nn \g_@@_data_ior { UnicodeData.txt }
-      \ior_close:N \g_@@_data_ior
-    \group_end:
-  }
-%    \end{macrocode}
 %
 %    \begin{macrocode}
 %</package>

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-code.tex	2022-08-31 20:19:45 UTC (rev 64251)
@@ -52,6 +52,7 @@
 %% l3unicode.dtx  (with options: `package')
 %% l3text.dtx  (with options: `package')
 %% l3text-case.dtx  (with options: `package')
+%% l3text-map.dtx  (with options: `package')
 %% l3text-purify.dtx  (with options: `package')
 %% l3candidates.dtx  (with options: `package')
 %% l3legacy.dtx  (with options: `package')
@@ -70,7 +71,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx
-\def\ExplFileDate{2022-08-23}%
+\def\ExplFileDate{2022-08-30}%
 \begingroup
   \def\next{\endgroup}%
   \expandafter\ifx\csname PackageError\endcsname\relax
@@ -8892,27 +8893,92 @@
   }
 \cs_generate_variant:Nn \__char_to_utfviii_bytes_output:nnn { f }
 \cs_new:Npn \__char_to_utfviii_bytes_end: { }
-\cs_new:Npn \char_to_nfd:N #1
+\bool_lazy_or:nnTF
+  { \sys_if_engine_luatex_p: }
+  { \sys_if_engine_xetex_p: }
   {
-    \cs_if_exist:cTF { c__char_nfd_ \token_to_str:N #1 _ tl }
+    \cs_new:Npn \char_to_nfd:N #1
       {
-        \exp_after:wN \exp_after:wN \exp_after:wN \__char_to_nfd:Nw
-          \exp_after:wN \exp_after:wN \exp_after:wN #1
-            \cs:w c__char_nfd_ \token_to_str:N #1 _ tl \cs_end:
-              \s__char_stop
+        \cs_if_exist:cTF { c__char_nfd_ \token_to_str:N #1 _ tl }
+          {
+            \exp_after:wN \exp_after:wN \exp_after:wN \__char_to_nfd:Nw
+              \exp_after:wN \exp_after:wN \exp_after:wN #1
+                \cs:w c__char_nfd_ \token_to_str:N #1 _tl \cs_end:
+                  \s__char_stop
+          }
+          { \exp_not:n {#1} }
       }
-      { \exp_not:n {#1} }
+    \cs_new_eq:NN \__char_to_nfd:n \char_to_nfd:N
+    \cs_generate_variant:Nn \__char_to_nfd:n { e }
+    \cs_new:Npn \__char_to_nfd:Nw #1#2#3 \s__char_stop
+      {
+        \__char_to_nfd:e
+          { \char_generate:nn { `#2 } { \__char_change_case_catcode:N #1 } }
+        \tl_if_blank:nF {#3}
+          {
+            \__char_to_nfd:e
+               { \char_generate:nn { `#3 } { \char_value_catcode:n { `#3 } } }
+          }
+      }
+    \cs_new:Npn \char_to_nfd:n #1
+      {
+        \__char_to_nfd:e { \char_generate:nn {#1} { \char_value_catcode:n {#1} } }
+      }
   }
-\cs_set_eq:NN \__char_to_nfd:n \char_to_nfd:N
-\cs_new:Npn \__char_to_nfd:Nw #1#2#3 \s__char_stop
   {
-    \exp_args:Ne \__char_to_nfd:n
-      { \char_generate:nn { `#2 } { \__char_change_case_catcode:N #1 } }
-    \tl_if_blank:nF {#3}
+    \cs_new:Npn \char_to_nfd:N #1 { \exp_not:n {#1} }
+    \cs_new:Npn \char_to_nfd:n #1
       {
-        \exp_args:Ne \__char_to_nfd:n
-          { \char_generate:nn { `#3 } { \char_value_catcode:n { `#3 } } }
+        \int_compare:nNnTF {#1} > { "80 }
+          { \exp_args:Ne \__char_to_nfd:n { \__char_nfd_generate:n {#1} } }
+          { \__char_nfd_generate:n {#1} }
       }
+    \cs_new:Npn \__char_to_nfd:n #1
+      {
+        \cs_if_exist:cTF { c__char_nfd_ \tl_to_str:n {#1} _ tl }
+          {
+            \exp_after:wN \exp_after:wN \exp_after:wN \__char_to_nfd:w
+              \cs:w c__char_nfd_ \tl_to_str:n {#1} _tl \cs_end:
+                \s__char_stop
+          }
+          { \exp_not:n {#1} }
+      }
+    \cs_new:Npn \__char_to_nfd:w #1#2 \s__char_stop
+      {
+        \__char_to_nfd:n {#1}
+        \tl_if_blank:nF {#2}
+          { \__char_to_nfd:n {#2} }
+      }
+     \cs_new:Npn \__char_nfd_generate:n #1
+       {
+         \use:e
+           {
+             \exp_not:N \__char_nfd_generate:nnnn
+               \char_to_utfviii_bytes:n {#1}
+           }
+       }
+      \cs_new:Npn \__char_nfd_generate:nnnn #1#2#3#4
+        {
+          \tl_if_blank:nTF {#2}
+            { \char_generate:nn {#1} { \char_value_catcode:n {#1} } }
+            {
+              \exp_after:wN \exp_after:wN \exp_after:wN
+                \exp_not:N \char_generate:nn {#1} { 13 }
+              \exp_after:wN \exp_after:wN \exp_after:wN
+                \exp_not:N \char_generate:nn {#2} { 13 }
+              \tl_if_blank:nF {#3}
+                {
+                  \exp_after:wN \exp_after:wN \exp_after:wN
+                    \exp_not:N \char_generate:nn {#3} { 13 }
+                  \tl_if_blank:nF {#4}
+                    {
+                      \exp_after:wN \exp_after:wN \exp_after:wN
+                        \exp_not:N \char_generate:nn {#4} { 13 }
+                    }
+                }
+            }
+
+        }
   }
 \cs_new:Npn \char_lowercase:N #1
   { \__char_change_case:nNN { lower } \char_value_lccode:n #1 }
@@ -30233,20 +30299,19 @@
         \__pdf_backend_compress_objects:n { \c_false_bool }
       }
   }
-\cs_new_protected:Npn \pdf_object_new:nn #1#2
-  { \__pdf_backend_object_new:nn {#1} {#2} }
-\prg_new_conditional:Npnn \pdf_object_if_exist:n #1 { p , T , F , TF }
+\cs_new_protected:Npn \pdf_object_new:n #1
   {
-    \int_if_exist:cTF { c__pdf_backend_object_ \tl_to_str:n {#1} _int }
-     { \prg_return_true: }
-     { \prg_return_false:}
+    \__pdf_backend_object_new:n {#1}
+    \cs_new_eq:cc
+      { c__pdf_backend_object_ \tl_to_str:n {#1} _int }
+      { c__pdf_object_ \tl_to_str:n {#1} _int }
   }
-\cs_new_protected:Npn \pdf_object_write:nn #1#2
+\cs_new_protected:Npn \pdf_object_write:nnn #1#2#3
   {
-    \__pdf_backend_object_write:nn {#1} {#2}
+    \__pdf_backend_object_write:nnn {#1} {#2} {#3}
     \bool_gset_true:N \g__pdf_init_bool
   }
-\cs_generate_variant:Nn \pdf_object_write:nn { nx }
+\cs_generate_variant:Nn \pdf_object_write:nnn { nnx }
 \cs_new:Npn \pdf_object_ref:n #1 { \__pdf_backend_object_ref:n {#1} }
 \cs_new_protected:Npn \pdf_object_unnamed_write:nn #1#2
   {
@@ -30255,6 +30320,12 @@
   }
 \cs_generate_variant:Nn \pdf_object_unnamed_write:nn { nx }
 \cs_new:Npn \pdf_object_ref_last: { \__pdf_backend_object_last: }
+\prg_new_conditional:Npnn \pdf_object_if_exist:n #1 { p , T , F , TF }
+  {
+    \int_if_exist:cTF { c__pdf_object_ \tl_to_str:n {#1} _int }
+      \prg_return_true:
+      \prg_return_false:
+  }
 \cs_new:Npn \pdf_pageobject_ref:n #1
   { \__pdf_backend_pageobject_ref:n {#1} }
 \prg_new_conditional:Npnn \pdf_version_compare:Nn #1#2 { p , T , F , TF }
@@ -30317,6 +30388,19 @@
     \hbox_to_zero:n
       { \__pdf_backend_destination:nnnn {#1} {#2} {#3} {#4} }
   }
+\prop_new:N \g__pdf_object_prop
+\cs_new_protected:Npn \pdf_object_new:nn #1#2
+  {
+    \prop_gput:Nnn \g__pdf_object_prop {#1} {#2}
+    \__pdf_backend_object_new:n {#1}
+  }
+\cs_new_protected:Npn \pdf_object_write:nn #1#2
+  {
+    \exp_args:Nnx \__pdf_backend_object_write:nnn
+      {#1} { \prop_item:Nn \g__pdf_object_prop {#1} } {#2}
+    \bool_gset_true:N \g__pdf_init_bool
+  }
+\cs_generate_variant:Nn \pdf_object_write:nn { nx }
 %% File: l3coffins.dtx
 \box_new:N \l__coffin_internal_box
 \dim_new:N \l__coffin_internal_dim
@@ -31644,143 +31728,219 @@
 \prop_gput:Nnn \g_msg_module_type_prop { luatex } { }
 %% File: l3unicode.dtx
 \ior_new:N \g__char_data_ior
-\bool_lazy_or:nnTF { \sys_if_engine_luatex_p: } { \sys_if_engine_xetex_p: }
-  {
-    \group_begin:
-      \cs_set:Npn \__char_generate_char:n #1
-        { \tex_detokenize:D \tex_expandafter:D { \tex_Uchar:D " #1 } }
-      \cs_set:Npx \__char_generate:n #1
+\group_begin:
+  \bool_lazy_or:nnTF
+    { \sys_if_engine_luatex_p: }
+    { \sys_if_engine_xetex_p: }
+    {
+      \cs_set:Npn \__char_generate_other:n #1
+        { \tex_detokenize:D \tex_expandafter:D { \tex_Uchar:D #1 } }
+      \cs_set:Npn \__char_generate:n #1
         {
-          \exp_not:N \tex_unexpanded:D \exp_not:N \exp_after:wN
-            {
-              \exp_not:N \tex_Ucharcat:D
-                #1 ~
-                \tex_catcode:D #1 ~
-            }
+          \tex_unexpanded:D \exp_after:wN
+            { \tex_Ucharcat:D #1 ~ \tex_catcode:D #1 ~ }
         }
-      \ior_open:Nn \g__char_data_ior { UnicodeData.txt }
-      \cs_set_protected:Npn \__char_data_auxi:w
-        #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ; #8 ; #9 ;
+    }
+    {
+      \cs_set:Npn \__char_generate_other:n #1
         {
-          \tl_if_blank:nF {#6}
+          \tex_detokenize:D \tex_expandafter:D
+            { \tex_expanded:D { \__char_generate:n {#1} } }
+        }
+      \cs_set:Npn \__char_generate:n #1
+        {
+          \use:e
             {
-              \tl_if_head_eq_charcode:nNF {#6}  < % >
-                { \__char_data_auxii:w #1 ; #6 ~ \q_stop }
+              \exp_not:N \__char_generate:nnnn
+                \char_to_utfviii_bytes:n {#1}
             }
-          \__char_data_auxiii:w #1 ;
         }
-      \cs_set_protected:Npn \__char_data_auxii:w #1 ; #2 ~ #3 \q_stop
+      \cs_set:Npn \__char_generate:nnnn #1#2#3#4
         {
-          \tl_const:cx
-            { c__char_nfd_ \__char_generate_char:n {#1} _tl }
+          \tex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN
+            { \char_generate:nn {#1} { 13 } }
+          \tl_if_blank:nF {#2}
             {
-              \__char_generate:n { "#2 }
+              \tex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN
+                { \char_generate:nn {#2} { 13 } }
               \tl_if_blank:nF {#3}
-                { \__char_generate:n { "#3 } }
+                {
+                  \tex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN
+                    { \char_generate:nn {#3} { 13 } }
+                  \tl_if_blank:nF {#4}
+                    {
+                      \tex_unexpanded:D
+                        \exp_after:wN \exp_after:wN \exp_after:wN
+                          { \char_generate:nn {#4} { 13 } }
+                    }
+                }
             }
         }
-      \cs_set_protected:Npn \__char_data_auxiii:w
-        #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ~ \q_stop
+    }
+  \cs_set_protected:Npn \__char_data_auxi:w
+    #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ; #8 ; #9 ;
+    {
+      \tl_if_blank:nF {#6}
         {
-          \cs_set_nopar:Npn \l__char_tmpa_tl {#7}
-          \reverse_if:N \if_meaning:w \l__char_tmpa_tl \c_empty_tl
-            \cs_set_nopar:Npn \l__char_tmpb_tl {#5}
-            \reverse_if:N \if_meaning:w \l__char_tmpa_tl \l__char_tmpb_tl
-              \tl_const:cx
-                { c__char_titlecase_ \__char_generate_char:n {#1} _tl }
-                { \__char_generate:n { "#7 } }
-            \fi:
-          \fi:
+          \tl_if_head_eq_charcode:nNF {#6}  < % >
+            { \__char_data_auxii:w #1 ; #6 ~ \q_stop }
         }
-      \group_begin:
-        \char_set_catcode_space:n { `\  }%
-        \ior_map_variable:NNn \g__char_data_ior \l__char_tmpa_tl
-          {%
-            \if_meaning:w \l__char_tmpa_tl \c_space_tl
-              \exp_after:wN \ior_map_break:
-            \fi:
-            \exp_after:wN \__char_data_auxi:w \l__char_tmpa_tl \q_stop
-          }%
-      \group_end:
-      \ior_close:N \g__char_data_ior
-      \ior_open:Nn \g__char_data_ior { CaseFolding.txt }
+      \__char_data_auxiii:w #1 ;
+    }
+  \cs_set_protected:Npn \__char_data_auxii:w #1 ; #2 ~ #3 \q_stop
+    {
+      \tl_const:cx
+        { c__char_nfd_ \__char_generate_other:n { "#1 } _tl }
+        {
+          { \__char_generate:n { "#2 } }
+          {
+            \tl_if_blank:nF {#3}
+              { \__char_generate:n { "#3 } }
+            }
+        }
+    }
+  \cs_set_protected:Npn \__char_data_auxiii:w
+    #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ~ \q_stop
+    {
+      \cs_set_nopar:Npn \l__char_tmpa_tl {#7}
+      \reverse_if:N \if_meaning:w \l__char_tmpa_tl \c_empty_tl
+        \cs_set_nopar:Npn \l__char_tmpb_tl {#5}
+        \reverse_if:N \if_meaning:w \l__char_tmpa_tl \l__char_tmpb_tl
+          \tl_const:cx
+            { c__char_titlecase_ \__char_generate_other:n { "#1 } _tl }
+            { \__char_generate:n { "#7 } }
+        \fi:
+      \fi:
+    }
+  \ior_open:Nn \g__char_data_ior { UnicodeData.txt }
+  \group_begin:
+    \char_set_catcode_space:n { `\  }%
+    \ior_map_variable:NNn \g__char_data_ior \l__char_tmpa_tl
+      {%
+        \if_meaning:w \l__char_tmpa_tl \c_space_tl
+          \exp_after:wN \ior_map_break:
+        \fi:
+        \exp_after:wN \__char_data_auxi:w \l__char_tmpa_tl \q_stop
+      }%
+  \group_end:
+  \ior_open:Nn \g__char_data_ior { CaseFolding.txt }
+  \cs_set_protected:Npn \__char_data_auxi:w #1 ;~ #2 ;~ #3 ; #4 \q_stop
+    {
+      \if:w \tl_head:n { #2 ? } C
+        \reverse_if:N \if_int_compare:w
+          \char_value_lccode:n {"#1} = "#3 ~
+          \tl_const:cx
+            { c__char_foldcase_ \__char_generate_other:n { "#1 } _tl }
+            { \__char_generate:n { "#3 } }
+        \fi:
+      \else:
+        \if:w \tl_head:n { #2 ? } F
+          \__char_data_auxii:w #1 ~ #3 ~ \q_stop
+        \fi:
+      \fi:
+    }
+  \bool_lazy_or:nnF
+    { \sys_if_engine_luatex_p: }
+    { \sys_if_engine_xetex_p: }
+    {
       \cs_set_protected:Npn \__char_data_auxi:w #1 ;~ #2 ;~ #3 ; #4 \q_stop
         {
-          \if:w \tl_head:n { #2 ? } C
-            \reverse_if:N \if_int_compare:w
-              \char_value_lccode:n {"#1} = "#3 ~
-              \tl_const:cx
-                { c__char_foldcase_ \__char_generate_char:n {#1} _tl }
-                { \__char_generate:n { "#3 } }
-            \fi:
-          \else:
-            \if:w \tl_head:n { #2 ? } F
-              \__char_data_auxii:w #1 ~ #3 ~ \q_stop
-            \fi:
+          \if:w \tl_head:n { #2 ? } F
+            \__char_data_auxii:w #1 ~ #3 ~ \q_stop
           \fi:
         }
-      \cs_set_protected:Npn \__char_data_auxii:w #1 ~ #2 ~ #3 ~ #4 \q_stop
+    }
+  \cs_set_protected:Npn \__char_data_auxii:w #1 ~ #2 ~ #3 ~ #4 \q_stop
+    {
+      \tl_const:cx { c__char_foldcase_ \__char_generate_other:n { "#1 } _tl }
         {
-          \tl_const:cx { c__char_foldcase_ \__char_generate_char:n {#1} _tl }
+          \__char_generate:n { "#2 }
+          \__char_generate:n { "#3 }
+          \tl_if_blank:nF {#4}
+            { \__char_generate:n { \int_value:w "#4 } }
+        }
+    }
+  \ior_str_map_inline:Nn \g__char_data_ior
+    {
+      \reverse_if:N \if:w \c_hash_str \tl_head:w #1 \c_hash_str \q_stop
+        \__char_data_auxi:w #1 \q_stop
+      \fi:
+    }
+  \ior_close:N \g__char_data_ior
+  \ior_open:Nn \g__char_data_ior { SpecialCasing.txt }
+  \cs_set_protected:Npn \__char_data_auxi:w
+    #1 ;~ #2 ;~ #3 ;~ #4 ; #5 \q_stop
+    {
+      \use:n { \__char_data_auxii:w #1 ~ lower ~ #2 ~ } ~ \q_stop
+      \use:n { \__char_data_auxii:w #1 ~ upper ~ #4 ~ } ~ \q_stop
+      \str_if_eq:nnF {#3} {#4}
+        { \use:n { \__char_data_auxii:w #1 ~ title ~ #3 ~ } ~ \q_stop }
+    }
+  \cs_set_protected:Npn \__char_data_auxii:w
+    #1 ~ #2 ~ #3 ~ #4 ~ #5 \q_stop
+    {
+      \tl_if_empty:nF {#4}
+        {
+          \tl_const:cx { c__char_ #2 case_ \__char_generate_other:n { "#1 } _tl }
             {
-              \__char_generate:n { "#2 }
               \__char_generate:n { "#3 }
-              \tl_if_blank:nF {#4}
-                { \__char_generate:n { \int_value:w "#4 } }
+              \__char_generate:n { "#4 }
+              \tl_if_blank:nF {#5}
+                { \__char_generate:n { "#5 } }
             }
         }
-      \ior_str_map_inline:Nn \g__char_data_ior
+    }
+  \ior_str_map_inline:Nn \g__char_data_ior
+    {
+      \str_if_eq:eeTF { \tl_head:w #1 \c_hash_str \q_stop } { \c_hash_str }
         {
-          \reverse_if:N \if:w \c_hash_str \tl_head:w #1 \c_hash_str \q_stop
-            \__char_data_auxi:w #1 \q_stop
-          \fi:
+          \str_if_eq:eeT
+            {#1}
+            { \c_hash_str \c_space_tl Conditional~Mappings }
+            { \ior_map_break: }
         }
-      \ior_close:N \g__char_data_ior
-      \ior_open:Nn \g__char_data_ior { SpecialCasing.txt }
-      \cs_set_protected:Npn \__char_data_auxi:w
-        #1 ;~ #2 ;~ #3 ;~ #4 ; #5 \q_stop
+        { \__char_data_auxi:w #1 \q_stop }
+    }
+  \ior_close:N \g__char_data_ior
+\group_end:
+
+\ior_new:N \g__text_data_ior
+\group_begin:
+  \ior_open:Nn \g__text_data_ior { GraphemeBreakProperty.txt }
+  \cs_set_nopar:Npn \l__text_tmpa_str { }
+  \cs_set_nopar:Npn \l__text_tmpb_str { }
+  \cs_set_protected:Npn \__text_data_auxi:w #1 ;~ #2 ~ #3 \q_stop
+    {
+      \str_if_eq:VnF \l__text_tmpb_str {#2}
         {
-          \use:n { \__char_data_auxii:w #1 ~ lower ~ #2 ~ } ~ \q_stop
-          \use:n { \__char_data_auxii:w #1 ~ upper ~ #4 ~ } ~ \q_stop
-          \str_if_eq:nnF {#3} {#4}
-            { \use:n { \__char_data_auxii:w #1 ~ title ~ #3 ~ } ~ \q_stop }
-        }
-      \cs_set_protected:Npn \__char_data_auxii:w
-        #1 ~ #2 ~ #3 ~ #4 ~ #5 \q_stop
-        {
-          \tl_if_empty:nF {#4}
+          \str_if_empty:NF \l__text_tmpb_str
             {
-              \tl_const:cx { c__char_ #2 case_ \__char_generate_char:n {#1} _tl }
-                {
-                  \__char_generate:n { "#3 }
-                  \__char_generate:n { "#4 }
-                  \tl_if_blank:nF {#5}
-                    { \__char_generate:n { "#5 } }
-                }
+              \clist_const:cx { c__text_grapheme_ \l__text_tmpb_str _clist }
+                { \exp_after:wN \use_none:n \l__text_tmpa_str }
+              \cs_set_nopar:Npn \l__text_tmpa_str { }
             }
+          \cs_set_nopar:Npn \l__text_tmpb_str {#2}
         }
-      \ior_str_map_inline:Nn \g__char_data_ior
+      \__text_data_auxii:w #1 .. #1 .. #1 \q_stop
+    }
+  \cs_set_protected:Npn \__text_data_auxii:w #1 .. #2 .. #3 \q_stop
+    {
+      \cs_set_nopar:Npx \l__text_tmpa_str
         {
-          \str_if_eq:eeTF
-            { \tl_head:w #1 \c_hash_str \q_stop }
-            { \c_hash_str }
-            {
-              \str_if_eq:eeT
-                {#1}
-                { \c_hash_str \c_space_tl Conditional~Mappings }
-                { \ior_map_break: }
-            }
-            { \__char_data_auxi:w #1 \q_stop }
+          \l__text_tmpa_str ,
+          \tl_trim_spaces:n {#1} .. \tl_trim_spaces:n {#2}
         }
-      \ior_close:N \g__char_data_ior
-    \group_end:
-  }
-  {
-    \group_begin:
-      \ior_open:Nn \g__char_data_ior { UnicodeData.txt }
-      \ior_close:N \g__char_data_ior
-    \group_end:
-  }
+    }
+  \ior_str_map_inline:Nn \g__text_data_ior
+    {
+      \str_if_eq:eeF { \tl_head:w #1 \c_hash_str \q_stop } { \c_hash_str }
+        {
+          \tl_if_blank:nF {#1}
+            { \__text_data_auxi:w #1 \q_stop }
+        }
+    }
+  \ior_close:N \g__text_data_ior
+\group_end:
 %% File: l3text.dtx
 \cs_generate_variant:Nn \tl_if_head_eq_meaning_p:nN { o }
 \scan_new:N \s__text_stop
@@ -31791,6 +31951,7 @@
 \cs_new:Npn \__text_use_i_delimit_by_q_recursion_stop:nw
   #1 #2 \q__text_recursion_stop {#1}
 \__kernel_quark_new_test:N \__text_if_q_recursion_tail_stop_do:Nn
+\__kernel_quark_new_test:N \__text_if_q_recursion_tail_stop_do:nn
 \scan_new:N \s__text_recursion_tail
 \scan_new:N \s__text_recursion_stop
 \cs_new:Npn \__text_use_i_delimit_by_s_recursion_stop:nw
@@ -31935,6 +32096,89 @@
       }
       { \prg_return_false: }
   }
+\bool_lazy_or:nnTF
+  { \sys_if_engine_luatex_p: }
+  { \sys_if_engine_xetex_p: }
+  {
+    \cs_new:Npn \__text_codepoint_process:nN #1#2 { #1 {#2} }
+  }
+  {
+    \cs_new:Npn \__text_codepoint_process:nN #1#2
+      {
+        \int_compare:nNnTF { `#2 } > { "80 }
+          {
+            \int_compare:nNnTF { `#2 } < { "E0 }
+              { \__text_codepoint_process:nNN }
+              {
+                 \int_compare:nNnTF { `#2 } < { "F0 }
+                   { \__text_codepoint_process:nNNN }
+                   { \__text_codepoint_process:nNNNN }
+              }
+          }
+          { \use:n }
+            {#1} #2
+      }
+    \cs_new:Npn \__text_codepoint_process:nNN #1#2#3
+      { #1 {#2#3} }
+    \cs_new:Npn \__text_codepoint_process:nNNN #1#2#3#4
+      { #1 {#2#3#4} }
+    \cs_new:Npn \__text_codepoint_process:nNNNN #1#2#3#4#5
+      { #1 {#2#3#4#5} }
+  }
+\bool_lazy_or:nnTF
+  { \sys_if_engine_luatex_p: }
+  { \sys_if_engine_xetex_p: }
+  {
+    \prg_new_conditional:Npnn
+      \__text_codepoint_compare:nNn #1#2#3 { TF , p }
+      {
+        \int_compare:nNnTF { `#1 } #2 {#3}
+          \prg_return_true: \prg_return_false:
+      }
+  }
+  {
+    \prg_new_conditional:Npnn
+      \__text_codepoint_compare:nNn #1#2#3 { TF , p }
+      {
+        \int_compare:nNnTF { \__text_codepoint_compare:N #1 }
+            #2 {#3}
+          \prg_return_true: \prg_return_false:
+      }
+    \cs_new:Npn \__text_codepoint_compare:N #1
+      {
+        \if_int_compare:w `#1 > "80 \exp_stop_f:
+          \if_int_compare:w `#1 < "E0 \exp_stop_f:
+            \exp_after:wN \exp_after:wN \exp_after:wN
+              \__text_codepoint_compare:NN
+          \else:
+            \if_int_compare:w `#1 < "F0 \exp_stop_f:
+              \exp_after:wN \exp_after:wN \exp_after:wN
+              \exp_after:wN \exp_after:wN \exp_after:wN
+              \exp_after:wN \__text_codepoint_compare:NNN
+            \else:
+              \exp_after:wN \exp_after:wN \exp_after:wN
+              \exp_after:wN \exp_after:wN \exp_after:wN
+              \exp_after:wN \__text_codepoint_compare:NNNN
+            \fi:
+          \fi:
+        \else:
+          \exp_after:wN \__text_codepoint_compare_aux:N
+        \fi:
+          #1
+      }
+    \cs_new:Npn \__text_codepoint_compare_aux:N #1 { `#1 }
+    \cs_new:Npn \__text_codepoint_compare:NN #1#2
+      { (`#1 - "C0) * "40 + `#2 - "80 }
+    \cs_new:Npn \__text_codepoint_compare:NNN #1#2#3
+      { (`#1 - "E0) * "1000 + (`#2 - "80) * "40 + `#3 - "80 }
+    \cs_new:Npn \__text_codepoint_compare:NNNN #1#2#3#4
+      {
+          (`#1 - "F0) * "40000
+        + (`#2 - "80) * "1000
+        + (`#3 - "80) * "40
+        + `#4 - "80
+      }
+  }
 \tl_new:N \l_text_accents_tl
 \tl_set:Nn \l_text_accents_tl
   { \` \' \^ \~ \= \u \. \" \r \H \v \d \c \k \b \t }
@@ -33352,6 +33596,32 @@
     \cs_new_eq:cc { __text_change_case_title_hy-x-yiwn:nnnN }
       { __text_change_case_upper_hy-x-yiwn:nnnN }
   }
+\cs_new:cpn { __text_change_case_lower_la-x-medieval:nnnN } #1#2#3#4
+  {
+    \int_compare:nNnTF { `#4 } = { `V }
+      {
+        \__text_change_case_store:e
+          {
+            \char_generate:nn { `u } { \__text_char_catcode:N #4 }
+          }
+        \use:c { __text_change_case_char_next_ #2 :nn }
+          {#2} {#3}
+      }
+      { \__text_change_case_char:nnnN {#1} {#2} {#3} #4 }
+  }
+\cs_new:cpn { __text_change_case_upper_la-x-medieval:nnnN } #1#2#3#4
+  {
+    \int_compare:nNnTF { `#4 } = { `u }
+      {
+        \__text_change_case_store:e
+          {
+            \char_generate:nn { `V } { \__text_char_catcode:N #4 }
+          }
+        \use:c { __text_change_case_char_next_ #2 :nn }
+          {#2} {#3}
+      }
+      { \__text_change_case_char:nnnN {#1} {#2} {#3} #4 }
+  }
 \bool_lazy_or:nnT
   { \sys_if_engine_luatex_p: }
   { \sys_if_engine_xetex_p: }
@@ -34622,6 +34892,355 @@
           }
       }
   }
+%% File: l3text-map.dtx
+\cs_new:Npn \text_map_function:nN #1#2
+  { \exp_args:Ne \__text_map_function:nN { \text_expand:n {#1} } #2 }
+\cs_new:Npn \__text_map_function:nN #1#2
+  {
+    \__text_map_loop:Nnw #2 { } #1
+      \q__text_recursion_tail \q__text_recursion_stop
+    \prg_break_point:Nn \text_map_break: { }
+  }
+\cs_new:Npn \__text_map_loop:Nnw #1#2#3 \q__text_recursion_stop
+  {
+    \tl_if_head_is_N_type:nTF {#3}
+      { \__text_map_N_type:NnN }
+      {
+        \tl_if_head_is_group:nTF {#3}
+          { \__text_map_group:Nnn }
+          { \__text_map_space:Nnw }
+      }
+    #1 {#2} #3 \q__text_recursion_stop
+  }
+\cs_new:Npn \__text_map_group:Nnn #1#2#3
+  {
+    \__text_map_output:Nn #1 {#2}
+    {
+      \__text_map_loop:Nnw #1 { } #2
+        \q__text_recursion_tail \q__text_recursion_stop
+      \prg_break_point:Nn \text_map_break: { }
+    }
+    \__text_map_loop:Nnw #1 { }
+  }
+\use:x
+  { \cs_new:Npn \exp_not:N \__text_map_space:Nnw ##1##2 \c_space_tl }
+  {
+    \__text_map_output:Nn #1 {#2}
+    #1 { ~ }
+    \__text_map_loop:Nnw #1 { }
+  }
+\cs_new:Npn \__text_map_N_type:NnN #1#2#3
+  {
+    \__text_if_q_recursion_tail_stop_do:Nn #3
+      {
+        \__text_map_output:Nn #1 {#2}
+        \text_map_break:
+      }
+    \token_if_cs:NTF #3
+      {
+        \__text_map_output:Nn #1 {#2}
+        #1 {#3}
+        \__text_map_loop:Nnw #1 { }
+      }
+      {
+        \__text_codepoint_process:nN
+          { \__text_map_codepoint:Nnn #1 {#2} } #3
+      }
+  }
+\cs_new:Npn \__text_map_codepoint:Nnn #1#2#3
+  {
+    \__text_codepoint_compare:nNnTF {#3} = { "0D }
+      {
+        \__text_map_output:Nn #1 {#2}
+        \__text_map_CR:Nnw #1 {#3}
+      }
+      {
+        \__text_codepoint_compare:nNnTF {#3} = { "200D }
+          { \__text_map_loop:Nnw #1 {#2#3} }
+          { \__text_map_class:Nnnn #1 {#2} {#3} { Control } }
+      }
+  }
+\cs_new:Npn \__text_map_CR:Nnw #1#2#3 \q__text_recursion_stop
+  {
+    \tl_if_head_is_N_type:nTF {#3}
+      { \__text_map_CR:NnN #1 {#2} }
+      {
+        #1 {#2}
+        \__text_map_loop:Nnw #1 { }
+      }
+        #3 \q__text_recursion_stop
+  }
+\cs_new:Npn \__text_map_CR:NnN #1#2#3
+  {
+    \__text_if_q_recursion_tail_stop_do:Nn #3
+      {
+        #1 {#2}
+        \text_map_break:
+      }
+    \bool_lazy_and:nnTF
+      { ! \token_if_cs_p:N #3 }
+      { \int_compare_p:nNn { `#3 } = { "0A } }
+      {
+        \__text_map_output:Nn #1 {#2#3}
+        \__text_map_loop:Nnw #1 { }
+      }
+      { \__text_map_loop:Nnw #1 { } #3 }
+  }
+\cs_new:Npn \__text_map_class:Nnnn #1#2#3#4
+  {
+    \exp_args:Nv \__text_map_class:nNnnn { c__text_grapheme_ #4 _clist }
+      #1 {#2} {#3} {#4}
+  }
+\cs_new:Npn \__text_map_class:nNnnn #1#2#3#4#5
+  {
+    \__text_map_class_loop:Nnnnw #2 {#3} {#4} {#5}
+      #1 , \q__text_recursion_tail .. , \q__text_recursion_stop
+  }
+\cs_new:Npn \__text_map_class_loop:Nnnnw #1#2#3#4 #5 .. #6 ,
+  {
+    \__text_if_q_recursion_tail_stop_do:nn {#5}
+      { \use:c { __text_map_not_ #4 :Nnn } #1 {#2} {#3} }
+    \__text_codepoint_compare:nNnTF {#3} < { "#5 }
+      {
+        \__text_map_class_end:nw
+          { \use:c { __text_map_not_ #4 :Nnn } #1 {#2} {#3} }
+      }
+      {
+        \__text_codepoint_compare:nNnTF {#3} > { "#6 }
+          { \__text_map_class_loop:Nnnnw #1 {#2} {#3} {#4} }
+          {
+            \__text_map_class_end:nw
+              { \use:c { __text_map_ #4 :Nnn } #1 {#2} {#3} }
+          }
+      }
+  }
+\cs_new:Npn \__text_map_class_end:nw #1#2 \q__text_recursion_stop {#1}
+\cs_new:Npn \__text_map_Control:Nnn #1#2#3
+  {
+    \__text_map_output:Nn #1 {#2}
+    \__text_map_output:Nn #1 {#3}
+    \__text_map_loop:Nnw #1 { }
+  }
+\cs_new:Npn \__text_map_Extend:Nnn #1#2#3
+  { \__text_map_loop:Nnw #1 {#2#3} }
+\cs_new_eq:NN \__text_map_SpacingMark:Nnn \__text_map_Extend:Nnn
+\cs_new:Npn \__text_map_Prepend:Nnn #1#2#3
+  {
+    \__text_map_output:Nn #1 {#2}
+    \__text_map_lookahead:NnNw #1 {#3} \__text_map_Prepend_aux:Nnn
+  }
+\cs_new:Npn \__text_map_Prepend_aux:Nnn #1#2#3
+  {
+    \bool_lazy_or:nnTF
+      { \__text_codepoint_compare_p:nNn {#3} = { "0A } }
+      { \__text_codepoint_compare_p:nNn {#3} = { "0D } }
+      {
+        #1 {#2}
+        \__text_map_loop:Nnw #1 {#3}
+      }
+      {
+        \exp_args:NV \__text_map_Prepend:nNnn
+          \c__text_grapheme_Control_clist
+          #1 {#2} {#3}
+      }
+  }
+\cs_new:Npn \__text_map_Prepend:nNnn #1#2#3#4
+  {
+    \__text_map_Prepend_loop:Nnnw #2 {#3} {#4}
+      #1 , \q__text_recursion_tail .. , \q__text_recursion_stop
+  }
+\cs_new:Npn \__text_map_Prepend_loop:Nnnw #1#2#3 #4 .. #5 ,
+  {
+    \__text_if_q_recursion_tail_stop_do:nn {#4}
+      { \__text_map_loop:Nnw #1 {#2#3} }
+    \__text_codepoint_compare:nNnTF {#3} < { "#4 }
+      {
+        \__text_map_class_end:nw
+          { \__text_map_loop:Nnw #1 {#2#3} }
+      }
+      {
+        \__text_codepoint_compare:nNnTF {#3} > { "#5 }
+          { \__text_map_Prepend_loop:Nnnw #1 {#2} {#3} }
+          {
+            \__text_map_class_end:nw
+              { \__text_map_loop:Nnw #1 {#2} #3 }
+          }
+      }
+  }
+\cs_new:Npn \__text_map_not_Control:Nnn #1#2#3
+  { \__text_map_class:Nnnn #1 {#2} {#3} { Extend } }
+\cs_new:Npn \__text_map_not_Extend:Nnn #1#2#3
+  { \__text_map_class:Nnnn #1 {#2} {#3} { SpacingMark } }
+\cs_new:Npn \__text_map_not_SpacingMark:Nnn #1#2#3
+  { \__text_map_class:Nnnn #1 {#2} {#3} { Prepend } }
+\cs_new:Npn \__text_map_not_Prepend:Nnn #1#2#3
+  { \__text_map_class:Nnnn #1 {#2} {#3} { L } }
+\cs_new:Npn \__text_map_not_L:Nnn #1#2#3
+  { \__text_map_class:Nnnn #1 {#2} {#3} { LV } }
+\cs_new:Npn \__text_map_not_LV:Nnn #1#2#3
+  { \__text_map_class:Nnnn #1 {#2} {#3} { V } }
+\cs_new:Npn \__text_map_not_V:Nnn #1#2#3
+  { \__text_map_class:Nnnn #1 {#2} {#3} { LVT } }
+\cs_new:Npn \__text_map_not_LVT:Nnn #1#2#3
+  { \__text_map_class:Nnnn #1 {#2} {#3} { T } }
+\cs_new:Npn \__text_map_not_T:Nnn #1#2#3
+  { \__text_map_class:Nnnn #1 {#2} {#3} { Regional_Indicator } }
+\cs_new:Npn \__text_map_not_Regional_Indicator:Nnn #1#2#3
+  {
+    \__text_map_output:Nn #1 {#2}
+    \__text_map_loop:Nnw #1 {#3}
+  }
+\cs_new:Npn \__text_map_L:Nnn #1#2#3
+  {
+    \__text_map_output:Nn #1 {#2}
+    \__text_map_hangul:Nnnw
+      #1 {#3} { L ; V ; LV ; LVT }
+  }
+\cs_new:Npn \__text_map_LV:Nnn #1#2#3
+  {
+    \__text_map_output:Nn #1 {#2}
+    \__text_map_hangul:Nnnw
+      #1 {#3} { V ; T }
+  }
+\cs_new_eq:NN \__text_map_V:Nnn \__text_map_LV:Nnn
+\cs_new:Npn \__text_map_LVT:Nnn #1#2#3
+  {
+    \__text_map_output:Nn #1 {#2}
+    \__text_map_hangul:Nnnw
+      #1 {#3} { T }
+  }
+\cs_new_eq:NN \__text_map_T:Nnn \__text_map_LVT:Nnn
+\cs_new:Npn \__text_map_hangul:Nnnw #1#2#3#4 \q__text_recursion_stop
+  {
+    \tl_if_head_is_N_type:nTF {#4}
+      { \__text_map_hangul:NnnN #1 {#2} {#3} }
+      {
+        #1 {#2}
+        \__text_map_loop:Nnw #1 { }
+      }
+    #4 \q__text_recursion_stop
+  }
+\cs_new:Npn \__text_map_hangul:NnnN #1#2#3#4
+  {
+    \__text_if_q_recursion_tail_stop_do:Nn #4
+      {
+        #1 {#2}
+        \text_map_break:
+      }
+    \token_if_cs:NTF #4
+      {
+        #1 {#2}
+        \__text_map_loop:Nnw #1 { }
+      }
+      {
+        \__text_codepoint_process:nN
+          { \__text_map_hangul:Nnnn #1 {#2} {#3} } #4
+      }
+  }
+\cs_new:Npn \__text_map_hangul:Nnnn #1#2#3#4
+  {
+    \__text_map_hangul_aux:Nnnw #1 {#2} {#4}
+      #3 ; \q_recursion_tail ; \q_recursion_stop
+  }
+\cs_new:Npn \__text_map_hangul_aux:Nnnw #1#2#3#4 ;
+  {
+    \quark_if_recursion_tail_stop_do:nn {#4}
+      { \__text_map_loop:Nnw #1 {#2} #3 }
+    \exp_args:Nv \__text_map_hangul:nNnnnw { c__text_grapheme_ #4 _clist }
+      #1 {#2} {#3} {#4}
+  }
+\cs_new:Npn \__text_map_hangul:nNnnnw #1#2#3#4#5#6  \q_recursion_stop
+  {
+    \__text_map_hangul_loop:Nnnnnw #2 {#3} {#4} {#5} {#6}
+      #1 , \q__text_recursion_tail .. , \q__text_recursion_stop
+  }
+\cs_new:Npn \__text_map_hangul_loop:Nnnnnw #1#2#3#4#5 #6 .. #7 ,
+  {
+    \__text_if_q_recursion_tail_stop_do:nn {#6}
+      { \__text_map_hangul_next:Nnnn #1 {#2} {#3} {#5} }
+    \__text_codepoint_compare:nNnTF {#3} < { "#6 }
+      {
+        \__text_map_hangul_end:nw
+          { \__text_map_hangul_next:Nnnn #1 {#2} {#3} {#5} }
+      }
+      {
+        \__text_codepoint_compare:nNnTF {#3} > { "#7 }
+          { \__text_map_hangul_loop:Nnnnnw #1 {#2} {#3} {#4} {#5} }
+          {
+            \__text_map_hangul_end:nw
+              { \use:c { __text_map_hangul_ #4 :Nnn } #1 {#2} {#3} }
+          }
+      }
+  }
+\cs_new:Npn \__text_map_hangul_next:Nnnn #1#2#3#4
+  { \__text_map_hangul_aux:Nnnw #1 {#2} {#3} #4 \q_recursion_stop }
+\cs_new:Npn \__text_map_hangul_end:nw #1#2 \q__text_recursion_stop {#1}
+\cs_new:Npn \__text_map_hangul_L:Nnn #1#2#3
+  {
+    \__text_map_hangul:Nnnw
+      #1 {#2#3} { L V { LV } { LVT } }
+  }
+\cs_new:Npn \__text_map_hangul_LV:Nnn #1#2#3
+  {
+    \__text_map_hangul:Nnnw
+      #1 {#2#3} { VT }
+  }
+\cs_new_eq:NN \__text_map_hangul_V:Nnn \__text_map_hangul_LV:Nnn
+\cs_new:Npn \__text_map_hangul_LVT:Nnn #1#2#3
+  {
+    \__text_map_hangul:Nnnw
+      #1 {#2#3} { T }
+  }
+\cs_new_eq:NN \__text_map_hangul_T:Nnn \__text_map_hangul_LVT:Nnn
+\cs_new:Npn \__text_map_Regional_Indicator:Nnn #1#2#3
+  {
+    \__text_map_output:Nn #1 {#2}
+    \__text_map_lookahead:NnNw #1 {#3} \__text_map_Regional_Indicator_aux:Nnn
+  }
+\cs_new:Npn \__text_map_Regional_Indicator_aux:Nnn #1#2#3
+  {
+    \bool_lazy_or:nnTF
+      { \__text_codepoint_compare_p:nNn {#3} < { "1F1E6 } }
+      { \__text_codepoint_compare_p:nNn {#3} > { "1F1FF } }
+      {
+        \__text_map_loop:Nnw #1 {#2} #3
+      }
+      { \__text_map_loop:Nnw #1 {#2#3} }
+  }
+\cs_new:Npn \__text_map_lookahead:NnNw #1#2#3#4 \q__text_recursion_stop
+  {
+    \tl_if_head_is_N_type:nTF {#4}
+      { \__text_map_lookahead:NnNN #1 {#2} #3 }
+      { \__text_map_loop:Nnw #1 {#2} }
+    #4 \q__text_recursion_stop
+  }
+\cs_new:Npn \__text_map_lookahead:NnNN #1#2#3#4
+  {
+    \__text_if_q_recursion_tail_stop_do:Nn #4 { #1 {#2} }
+    \token_if_cs:NTF #4
+      {
+        #1 {#2}
+        \__text_map_loop:Nnw #1 { }
+      }
+      { \__text_codepoint_process:nN { #3 #1 {#2} } }
+        #4
+  }
+\cs_new:Npn \__text_map_output:Nn #1#2
+  { \tl_if_blank:nF {#2} { #1 {#2} } }
+\cs_new:Npn \text_map_break:
+  { \prg_map_break:Nn \text_map_break: { } }
+\cs_new:Npn \text_map_break:n
+  { \prg_map_break:Nn \text_map_break: }
+\cs_new_protected:Npn \text_map_inline:nn #1#2
+  {
+    \int_gincr:N \g__kernel_prg_map_int
+    \cs_gset_protected:cpn
+      { __text_map_ \int_use:N \g__kernel_prg_map_int :w } ##1 {#2}
+    \exp_args:Nnc \text_map_function:nN {#1}
+      { __text_map_ \int_use:N \g__kernel_prg_map_int :w }
+    \prg_break_point:Nn \text_map_break:
+      { \int_gdecr:N \g__kernel_prg_map_int }
+  }
 %% File: l3text-purify.dtx
 \__kernel_quark_new_test:N \__text_if_recursion_tail_stop:N
 \cs_new:Npn \text_purify:n #1

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3-generic.tex	2022-08-31 20:19:45 UTC (rev 64251)
@@ -19,7 +19,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx
-\def\ExplFileDate{2022-08-23}%
+\def\ExplFileDate{2022-08-30}%
 \let\ExplLoaderFileDate\ExplFileDate
 \begingroup
   \catcode`\_=11

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.ltx
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.ltx	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.ltx	2022-08-31 20:19:45 UTC (rev 64251)
@@ -19,7 +19,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx
-\def\ExplFileDate{2022-08-23}%
+\def\ExplFileDate{2022-08-30}%
 \let\ExplLoaderFileDate\ExplFileDate
 \begingroup
   \catcode`\_=11

Modified: trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty	2022-08-31 20:18:20 UTC (rev 64250)
+++ trunk/Master/texmf-dist/tex/latex/l3kernel/expl3.sty	2022-08-31 20:19:45 UTC (rev 64251)
@@ -19,7 +19,7 @@
 %% and all files in that bundle must be distributed together.
 %% 
 %% File: expl3.dtx
-\def\ExplFileDate{2022-08-23}%
+\def\ExplFileDate{2022-08-30}%
 \let\ExplLoaderFileDate\ExplFileDate
 \ProvidesPackage{expl3}
   [%



More information about the tex-live-commits mailing list.