diff options
Diffstat (limited to 'Master/texmf-dist/source/latex')
58 files changed, 1281 insertions, 241 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx index 63f43014382..ebf703b25fa 100644 --- a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx @@ -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 % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3.ins b/Master/texmf-dist/source/latex/l3kernel/l3.ins index fbcc815d9f0..08949c097e8 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3.ins +++ b/Master/texmf-dist/source/latex/l3kernel/l3.ins @@ -106,6 +106,7 @@ and all files in that bundle must be distributed together. \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} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx index 69a59f065be..b881dbcf1d6 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx index 43a666d3ce8..963aae5ddbb 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx index 67767992eef..bc0fbb7eb59 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx index 155d51bc0e9..3279dda7629 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % @@ -643,9 +643,21 @@ % \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] diff --git a/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx b/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx index fac045495c4..6bc41991e51 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3cctab.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx index 34e78c62a35..4814d90427e 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx b/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx index 7d822312ebf..ded70d1248f 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3coffins.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3color.dtx b/Master/texmf-dist/source/latex/l3kernel/l3color.dtx index 33b28721edf..08b4f523e00 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3color.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3color.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx b/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx index 9fe0518b1f9..4867d5f5632 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3debug.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx b/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx index 4153116c3a3..ef7d77d064f 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3deprecation.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx index d8b2dc92548..6fdf2e694f1 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx @@ -85,7 +85,7 @@ and all files in that bundle must be distributed together. % require you to do updates, if the class changes.}} % % \author{\Team} -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % \maketitle % \tableofcontents % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx b/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx index bbf456084c1..b7dc2c22573 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3docstrip.dtx @@ -63,7 +63,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx index 71b45cc3cab..e975071462f 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx index 642f77afde6..7aaf7085de8 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx b/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx index af66b619641..cbe5351708f 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3flag.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx index 66e5be677de..8fa46b49dd3 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % \maketitle % % \begin{documentation} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx index 4b16b7c6fca..63c97ba5c15 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx index 9afe96a0695..74bd289d7ad 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx index daa67ea0a13..f39b77b9ee3 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx index ed26025368d..ca6d5091c75 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx index bc7e1770937..b24112a5a0c 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx index dbade2f5901..6fb84bfb97d 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx index efe9a6dfe92..facb50f0ea0 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx index 4cd51f0f893..ae5b968ecaf 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-random.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx index 1a56d98509b..f6122647e9c 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-round.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx index b566e3d1bb8..1f0fbfa6a89 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % \maketitle % % \begin{documentation} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx index a45b7856ff5..f19a864aab2 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx index 8d7c44dd352..da64860f8c5 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx @@ -49,7 +49,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx index c41a991af53..293154cad00 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fparray.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx index 1a6cb9ba77c..7fce0b7a2d1 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx b/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx index 5e49b94d4ef..be1fe6f7e31 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3intarray.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx b/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx index c26a6f0ccf1..d122477aeb7 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3kernel-functions.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx index d8313614d12..f626c9bdb25 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx b/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx index dc92bba1b5a..3d37094612d 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3legacy.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx b/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx index de35da4d948..bb5779f09eb 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3luatex.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx index 8c9ac087e8f..32f66edd92e 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3names.dtx b/Master/texmf-dist/source/latex/l3kernel/l3names.dtx index ce1ec1a49de..5566ead50cf 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3names.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3names.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx b/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx index 5a28010dde3..f02362df387 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3pdf.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % @@ -51,32 +51,18 @@ % % \section{Objects} % -% \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}. -% \end{function} -% \begin{function}[EXP, pTF, added=2020-05-15]{\pdf_object_if_exist:n} +% \begin{function}[added = 2022-08-23]{\pdf_object_new:n} % \begin{syntax} -% \cs{pdf_object_if_exist_p:n} \Arg{object} -% \cs{pdf_object_if_exist:nTF} \Arg{object} +% \cs{pdf_object_new:n} \Arg{object} % \end{syntax} -% Tests whether an object with name \Arg{object} has been defined. +% 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}[added = 2021-02-10] -% {\pdf_object_write:nn, \pdf_object_write:nx} +% +% \begin{function}[added = 2022-08-23] +% {\pdf_object_write:nnn, \pdf_object_write:nnx} % \begin{syntax} -% \cs{pdf_object_write:nn} \Arg{object} \Arg{content} +% \cs{pdf_object_write:nn} \Arg{object} \Arg{type} \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 @@ -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,12 +370,19 @@ } \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} % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\pdf_pageobject_ref:n} % \begin{macrocode} @@ -450,6 +492,34 @@ } % \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} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx index 542dec79c80..cb0d282a3cf 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx index 11b11e7e18e..6964f9ae473 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx index 9d39718d8ca..9723e115092 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3quark.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx b/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx index 049b1d46a47..5da0fa163f6 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3regex.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx index 41202a7949f..218bf5e507a 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx index 1c2b4884e4f..e829802de1c 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx b/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx index 88489875ac2..fac7fb0d1f3 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3sort.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx b/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx index 7c35f416828..78f6a12649a 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3str-convert.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3str.dtx b/Master/texmf-dist/source/latex/l3kernel/l3str.dtx index b9ad620959c..1ffa124f9ee 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3str.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3str.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx index f2fb078a965..2e9b5b939d4 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3sys.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx b/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx index 765a351667e..8a5615a1f63 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx @@ -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 , diff --git a/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx b/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx new file mode 100644 index 00000000000..8d8da0122f9 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3text-map.dtx @@ -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@latex-project.org} +% {latex-team@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 diff --git a/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx b/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx index 966e3518c78..3b5f5cb8c97 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3text-purify.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3text.dtx b/Master/texmf-dist/source/latex/l3kernel/l3text.dtx index df4f2fcde50..3e89563a5e9 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3text.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3text.dtx @@ -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} diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx index 728284c8ac7..912436441f3 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3tl-analysis.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx index 647442b82a1..8bdbf5098b7 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % diff --git a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx index 5583b55eef0..eb2ef81b195 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx @@ -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{macrocode} -\cs_new:Npn \char_to_nfd:N #1 +% \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} +\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} } + } + \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} } } } - { \exp_not: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 + { + \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 { - \exp_args:Ne \@@_to_nfd:n - { \char_generate:nn { `#3 } { \char_value_catcode:n { `#3 } } } + \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] % { diff --git a/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx b/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx index 8ae0f44fe87..737f9704843 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx @@ -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 + { + \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 { - \exp_not:N \tex_unexpanded:D \exp_not:N \exp_after:wN + \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,93 +199,140 @@ % 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: + \@@_generate:n { "#2 } + \@@_generate:n { "#3 } + \tl_if_blank:nF {#4} + { \@@_generate:n { \int_value:w "#4 } } } - \ior_close:N \g_@@_data_ior + } + \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 + \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} { - \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 } { - \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 } } - } + \@@_generate:n { "#3 } + \@@_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 } { - \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: } + } + { \@@_data_auxi:w #1 \q_stop } + } + \ior_close:N \g_@@_data_ior +\group_end: + +% \end{macrocode} +% +% \begin{macrocode} +%<@@=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} + { + \str_if_empty:NF \l_@@_tmpb_str { - \str_if_eq:eeT - {#1} - { \c_hash_str \c_space_tl Conditional~Mappings } - { \ior_map_break: } + \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} + } + \@@_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 + { + \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: - } -% \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: - } + } + \ior_close:N \g_@@_data_ior +\group_end: % \end{macrocode} % % \begin{macrocode} |