summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel')
-rw-r--r--macros/latex/contrib/l3kernel/CHANGELOG.md25
-rw-r--r--macros/latex/contrib/l3kernel/README.md4
-rw-r--r--macros/latex/contrib/l3kernel/expl3.dtx9
-rw-r--r--macros/latex/contrib/l3kernel/expl3.pdfbin622212 -> 622183 bytes
-rw-r--r--macros/latex/contrib/l3kernel/interface3.pdfbin1724914 -> 1732906 bytes
-rw-r--r--macros/latex/contrib/l3kernel/interface3.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3.ins3
-rw-r--r--macros/latex/contrib/l3kernel/l3basics.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3bootstrap.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3box.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3candidates.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3cctab.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3clist.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3coffins.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3color.dtx6
-rw-r--r--macros/latex/contrib/l3kernel/l3debug.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3deprecation.dtx31
-rw-r--r--macros/latex/contrib/l3kernel/l3doc.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3doc.pdfbin557935 -> 557935 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3docstrip.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3docstrip.pdfbin151752 -> 151749 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3expan.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3file.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3flag.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-assign.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-aux.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-basics.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-convert.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-expo.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-extended.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-functions.dtx282
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-logic.dtx17
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-parse.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-random.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-round.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-symbolic.dtx673
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-traps.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-trig.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-types.dtx184
-rw-r--r--macros/latex/contrib/l3kernel/l3fp.dtx136
-rw-r--r--macros/latex/contrib/l3kernel/l3fparray.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3int.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3intarray.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3kernel-functions.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3keys.dtx20
-rw-r--r--macros/latex/contrib/l3kernel/l3legacy.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3luatex.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3msg.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3names.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3news.pdfbin396222 -> 396222 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news01.pdfbin122959 -> 122959 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news02.pdfbin150919 -> 150919 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news03.pdfbin148747 -> 148747 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news04.pdfbin114754 -> 114754 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news05.pdfbin112524 -> 112524 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news06.pdfbin151591 -> 151591 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news07.pdfbin128344 -> 128344 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news08.pdfbin163484 -> 163484 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news09.pdfbin250159 -> 250159 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news10.pdfbin150302 -> 150302 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news11.pdfbin170102 -> 170102 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news12.pdfbin205020 -> 205020 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3pdf.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3prefixes.csv4
-rw-r--r--macros/latex/contrib/l3kernel/l3prefixes.pdfbin82529 -> 82661 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3prg.dtx13
-rw-r--r--macros/latex/contrib/l3kernel/l3prop.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3quark.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3regex.dtx6
-rw-r--r--macros/latex/contrib/l3kernel/l3seq.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3skip.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3sort.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3str-convert.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3str.dtx6
-rw-r--r--macros/latex/contrib/l3kernel/l3styleguide.pdfbin296260 -> 296258 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3styleguide.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3syntax-changes.pdfbin242906 -> 242903 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3syntax-changes.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3sys.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3term-glossary.pdfbin218060 -> 218059 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3term-glossary.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3text-case.dtx1366
-rw-r--r--macros/latex/contrib/l3kernel/l3text-map.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3text-purify.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3text.dtx41
-rw-r--r--macros/latex/contrib/l3kernel/l3tl-analysis.dtx43
-rw-r--r--macros/latex/contrib/l3kernel/l3tl.dtx10
-rw-r--r--macros/latex/contrib/l3kernel/l3token.dtx78
-rw-r--r--macros/latex/contrib/l3kernel/l3unicode.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/source3.pdfbin7389071 -> 7475976 bytes
-rw-r--r--macros/latex/contrib/l3kernel/source3.tex2
-rw-r--r--macros/latex/contrib/l3kernel/source3body.tex7
92 files changed, 2266 insertions, 812 deletions
diff --git a/macros/latex/contrib/l3kernel/CHANGELOG.md b/macros/latex/contrib/l3kernel/CHANGELOG.md
index 590abad03a..919e6779b6 100644
--- a/macros/latex/contrib/l3kernel/CHANGELOG.md
+++ b/macros/latex/contrib/l3kernel/CHANGELOG.md
@@ -7,6 +7,27 @@ this project uses date-based 'snapshot' version identifiers.
## [Unreleased]
+## [2023-10-23]
+
+### Added
+- `\text_titlecase_all:n(n)`
+- `\token_to_catcode:N`
+- Support for symbolic variables in fp input:
+ `\fp_new_variable:n`, `\fp_set_variable:nn` and `\fp_clear_variable:n`
+- Support for user-defined functions in fp expressions:
+ `\fp_new_function:n`, `\fp_set_function:nnn` and `\fp_clear_function:n`
+
+### Changed
+- Refine action of `\text_titlecase_first:n(n)` to be focussed strictly on
+ first (relevant) codepoint in the input
+
+### Deprecated
+- `\text_titlecase:n(n)` as ambiguous: replaced by `\text_titlecase_all:n(n)`
+
+### Fixed
+- Support arbitrary BCP-47 locales for case-changing overrides (issue \#1239)
+- Retain braces when ending titlecasing with some input structures
+
## [2023-10-10]
### Added
@@ -119,7 +140,6 @@ this project uses date-based 'snapshot' version identifiers.
- `\file_input_raw:n`
- `\int_if_zero:n(TF)`
- `\str_mdfive_hash:n`
-
### Changed
- Remove `\noexpand` inside math mode in `\text_expand:n`
- Re-implement `\dim_to_decimal_in_bp:n` and
@@ -1538,7 +1558,8 @@ this project uses date-based 'snapshot' version identifiers.
- Step functions have been added for dim variables,
e.g. `\dim_step_inline:nnnn`
-[Unreleased]: https://github.com/latex3/latex3/compare/2023-10-10...HEAD
+[Unreleased]: https://github.com/latex3/latex3/compare/2023-10-23...HEAD
+[2023-10-23]: https://github.com/latex3/latex3/compare/2023-10-10...2023-10-23
[2023-10-10]: https://github.com/latex3/latex3/compare/2023-08-29...2023-10-10
[2023-08-29]: https://github.com/latex3/latex3/compare/2023-08-11...2023-08-29
[2023-08-11]: https://github.com/latex3/latex3/compare/2023-08-03...2023-08-11
diff --git a/macros/latex/contrib/l3kernel/README.md b/macros/latex/contrib/l3kernel/README.md
index 7b368819d5..5f52ac444b 100644
--- a/macros/latex/contrib/l3kernel/README.md
+++ b/macros/latex/contrib/l3kernel/README.md
@@ -1,7 +1,7 @@
LaTeX3 Programming Conventions
==============================
-Release 2023-10-10
+Release 2023-10-23
Overview
--------
@@ -57,7 +57,7 @@ since the release of version 1.40.0 in 2007; `\expanded` was added for TeX Live
2019. Similarly, the full set of these utility primitives has been available in
XeTeX from the 2019 TeX Live release, and has always been available in LuaTeX
(some by Lua emulation). The Japanese pTeX and upTeX gained all of the above
-(except `\ifincsname`) for TeX Live 2019 `\ifincsname` for TeX Live 2020.
+(except `\ifincsname`) for TeX Live 2019 and `\ifincsname` for TeX Live 2020.
Starting from release 2023-05-15, the `\expanded` primitive is *required*.
Its slow emulation has been removed.
diff --git a/macros/latex/contrib/l3kernel/expl3.dtx b/macros/latex/contrib/l3kernel/expl3.dtx
index ea13fbeacf..09e21e4710 100644
--- a/macros/latex/contrib/l3kernel/expl3.dtx
+++ b/macros/latex/contrib/l3kernel/expl3.dtx
@@ -24,7 +24,7 @@
%
%<*driver|generic|package|2ekernel>
%</driver|generic|package|2ekernel>
-\def\ExplFileDate{2023-10-10}%
+\def\ExplFileDate{2023-10-23}%
%<*driver>
\documentclass[full]{l3doc}
\usepackage{graphicx}
@@ -51,7 +51,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -311,9 +311,8 @@
% or private.
%
% To allow clear separation of these two cases, the following convention
-% is used. In private functions and variables, two |_| characters are
-% added to the start of the module name. On the other hand, public
-% interfaces to not have these two |_| character. Thus
+% is used. To denote a private function or a private variable (of the module),
+% two |_| characters are used in front of the module name, e.g.
% \begin{verbatim}
% \module_foo:nnn
% \end{verbatim}
diff --git a/macros/latex/contrib/l3kernel/expl3.pdf b/macros/latex/contrib/l3kernel/expl3.pdf
index af52bd35c0..48ef0d9e7e 100644
--- a/macros/latex/contrib/l3kernel/expl3.pdf
+++ b/macros/latex/contrib/l3kernel/expl3.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/interface3.pdf b/macros/latex/contrib/l3kernel/interface3.pdf
index f8431c7347..d80ff728b7 100644
--- a/macros/latex/contrib/l3kernel/interface3.pdf
+++ b/macros/latex/contrib/l3kernel/interface3.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/interface3.tex b/macros/latex/contrib/l3kernel/interface3.tex
index 79d4cec3e9..ded23a7954 100644
--- a/macros/latex/contrib/l3kernel/interface3.tex
+++ b/macros/latex/contrib/l3kernel/interface3.tex
@@ -64,7 +64,7 @@ for those people who are interested.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2023-10-10}
+\date{Released 2023-10-23}
\pagenumbering{roman}
\maketitle
diff --git a/macros/latex/contrib/l3kernel/l3.ins b/macros/latex/contrib/l3kernel/l3.ins
index 52c65e4c8e..24f11d8f7b 100644
--- a/macros/latex/contrib/l3kernel/l3.ins
+++ b/macros/latex/contrib/l3kernel/l3.ins
@@ -92,6 +92,9 @@ and all files in that bundle must be distributed together.
\from{l3fp-trig.dtx} {package}
\from{l3fp-convert.dtx} {package}
\from{l3fp-random.dtx} {package}
+ \from{l3fp-types.dtx} {package}
+ \from{l3fp-symbolic.dtx}{package}
+ \from{l3fp-functions.dtx}{package}
\from{l3fparray.dtx} {package}
\from{l3cctab.dtx} {package}
\from{l3sort.dtx} {package}
diff --git a/macros/latex/contrib/l3kernel/l3basics.dtx b/macros/latex/contrib/l3kernel/l3basics.dtx
index 6b484105fe..00e159d817 100644
--- a/macros/latex/contrib/l3kernel/l3basics.dtx
+++ b/macros/latex/contrib/l3kernel/l3basics.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -1045,7 +1045,7 @@
% \end{texnote}
% \end{function}
%
-% \begin{function}[EXP, added = 2018-06-18]{\use:e}
+% \begin{function}[EXP, added = 2018-06-18, updated = 2023-07-05]{\use:e}
% \begin{syntax}
% \cs{use:e} \Arg{expandable tokens}
% \end{syntax}
diff --git a/macros/latex/contrib/l3kernel/l3bootstrap.dtx b/macros/latex/contrib/l3kernel/l3bootstrap.dtx
index e300bccc67..a42f358ae8 100644
--- a/macros/latex/contrib/l3kernel/l3bootstrap.dtx
+++ b/macros/latex/contrib/l3kernel/l3bootstrap.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3box.dtx b/macros/latex/contrib/l3kernel/l3box.dtx
index dfa6b3c451..5757653168 100644
--- a/macros/latex/contrib/l3kernel/l3box.dtx
+++ b/macros/latex/contrib/l3kernel/l3box.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3candidates.dtx b/macros/latex/contrib/l3kernel/l3candidates.dtx
index 6e455b099c..567969d545 100644
--- a/macros/latex/contrib/l3kernel/l3candidates.dtx
+++ b/macros/latex/contrib/l3kernel/l3candidates.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3cctab.dtx b/macros/latex/contrib/l3kernel/l3cctab.dtx
index 4192ec029a..794b53b5f4 100644
--- a/macros/latex/contrib/l3kernel/l3cctab.dtx
+++ b/macros/latex/contrib/l3kernel/l3cctab.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3clist.dtx b/macros/latex/contrib/l3kernel/l3clist.dtx
index 8fc2f6870b..bd8082cf34 100644
--- a/macros/latex/contrib/l3kernel/l3clist.dtx
+++ b/macros/latex/contrib/l3kernel/l3clist.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3coffins.dtx b/macros/latex/contrib/l3kernel/l3coffins.dtx
index 94824400de..cf046706b6 100644
--- a/macros/latex/contrib/l3kernel/l3coffins.dtx
+++ b/macros/latex/contrib/l3kernel/l3coffins.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3color.dtx b/macros/latex/contrib/l3kernel/l3color.dtx
index 3d225b2d22..2cdf604d02 100644
--- a/macros/latex/contrib/l3kernel/l3color.dtx
+++ b/macros/latex/contrib/l3kernel/l3color.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -330,7 +330,7 @@
%
% \subsection{Coloring math mode material}
%
-% Coloring math mode material using \cs{color_select:nn(n)} has some restrictions
+% Coloring math mode material using \cs[no-index]{color_select:nn(n)} has some restrictions
% and often leads to spacing issues and/or poor input syntax. Avoiding generating
% \tn{mathord} atoms whilst coloring only those parts of the input which are
% required needs careful handling. The functionality here covers this important
@@ -341,7 +341,7 @@
% \cs{color_math:nn} \Arg{color expression}\Arg{content}
% \cs{color_math:nnn} \Arg{model(s)} \Arg{value(s)} \Arg{content}
% \end{syntax}
-% Works as for \cs{color_select:n(n)} but applies color only to the math mode
+% Works as for \cs[no-index]{color_select:n(n)} but applies color only to the math mode
% \meta{content}. The function does not generate a group and the \meta{content}
% therefore retains its math atom states. Sub/superscripts are also properly
% handled.
diff --git a/macros/latex/contrib/l3kernel/l3debug.dtx b/macros/latex/contrib/l3kernel/l3debug.dtx
index 8efdc986cc..c351529d85 100644
--- a/macros/latex/contrib/l3kernel/l3debug.dtx
+++ b/macros/latex/contrib/l3kernel/l3debug.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3deprecation.dtx b/macros/latex/contrib/l3kernel/l3deprecation.dtx
index c9564f4080..98d8df40e5 100644
--- a/macros/latex/contrib/l3kernel/l3deprecation.dtx
+++ b/macros/latex/contrib/l3kernel/l3deprecation.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -549,6 +549,21 @@
% \end{macrocode}
% \end{macro}
%
+% \subsection{Deprecated \pkg{l3text} functions}
+%
+% \begin{macro}[EXP]{\text_titlecase:n}
+% \begin{macro}[EXP]{\text_titlecase:nn}
+% \begin{macrocode}
+\__kernel_patch_deprecation:nnNNpn { 2023-07-08 } { \text_titlecase_first:n }
+\cs_gset:Npn \text_titlecase:n #1
+ { \text_titlecase_first:n { \text_lowercase:n {#1} } }
+\__kernel_patch_deprecation:nnNNpn { 2023-07-08 } { \text_titlecase_first:nn }
+\cs_gset:Npn \text_titlecase:nn #1#2
+ { \text_titlecase_first:nn {#1} { \text_lowercase:n {#2} } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \subsection{Deprecated \pkg{l3tl} functions}
%
% \begin{macrocode}
@@ -574,12 +589,12 @@
\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_uppercase:nn }
\cs_gset:Npn \tl_upper_case:nn #1#2
{ \text_uppercase:nn {#1} {#2} }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase:n }
+\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase_first:n }
\cs_gset:Npn \tl_mixed_case:n #1
- { \text_titlecase:n {#1} }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase:nn }
+ { \text_titlecase_first:n {#1} }
+\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase_first:nn }
\cs_gset:Npn \tl_mixed_case:nn #1#2
- { \text_titlecase:nn {#1} {#2} }
+ { \text_titlecase_first:nn {#1} {#2} }
% \end{macrocode}
% \end{macro}
%
@@ -608,7 +623,7 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\char_to_nfd:Nm, \char_to_nfd:n}
+% \begin{macro}[EXP]{\char_to_nfd:N, \char_to_nfd:n}
% \begin{macrocode}
\__kernel_patch_deprecation:nnNNpn { 2022-10-09 } { \codepoint_to_nfd:n }
\cs_gset:Npn \char_to_nfd:N #1 { \codepoint_to_nfd:n {`#1} }
@@ -629,8 +644,8 @@
\cs_gset:Npn \char_lower_case:N { \text_lowercase:n }
\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_uppercase:n }
\cs_gset:Npn \char_upper_case:N { \text_uppercase:n }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase:n }
-\cs_gset:Npn \char_mixed_case:N { \text_titlecase:n }
+\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_titlecase_first:n }
+\cs_gset:Npn \char_mixed_case:N { \text_titlecase_first:n }
\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_casefold:n }
\cs_gset:Npn \char_fold_case:N { \str_casefold:n }
\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_lowercase:n }
diff --git a/macros/latex/contrib/l3kernel/l3doc.dtx b/macros/latex/contrib/l3kernel/l3doc.dtx
index ed675106ba..789095d104 100644
--- a/macros/latex/contrib/l3kernel/l3doc.dtx
+++ b/macros/latex/contrib/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 2023-10-10}
+% \date{Released 2023-10-23}
% \maketitle
% \tableofcontents
%
diff --git a/macros/latex/contrib/l3kernel/l3doc.pdf b/macros/latex/contrib/l3kernel/l3doc.pdf
index b8cd8d1e29..2612bef184 100644
--- a/macros/latex/contrib/l3kernel/l3doc.pdf
+++ b/macros/latex/contrib/l3kernel/l3doc.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3docstrip.dtx b/macros/latex/contrib/l3kernel/l3docstrip.dtx
index df2b7c63ab..59bd089ae6 100644
--- a/macros/latex/contrib/l3kernel/l3docstrip.dtx
+++ b/macros/latex/contrib/l3kernel/l3docstrip.dtx
@@ -2,7 +2,7 @@
%
%% File l3dosctrip.dtx
%
-% Copyright (C) 2012,2014-2023 The LaTeX Project
+% Copyright (C) 2012-2023 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
@@ -63,7 +63,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3docstrip.pdf b/macros/latex/contrib/l3kernel/l3docstrip.pdf
index 39d53ac5b9..4f43b61756 100644
--- a/macros/latex/contrib/l3kernel/l3docstrip.pdf
+++ b/macros/latex/contrib/l3kernel/l3docstrip.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3expan.dtx b/macros/latex/contrib/l3kernel/l3expan.dtx
index d4fe6b3a30..3bf2bd6153 100644
--- a/macros/latex/contrib/l3kernel/l3expan.dtx
+++ b/macros/latex/contrib/l3kernel/l3expan.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3file.dtx b/macros/latex/contrib/l3kernel/l3file.dtx
index 2d2ae6a183..af83fe4e08 100644
--- a/macros/latex/contrib/l3kernel/l3file.dtx
+++ b/macros/latex/contrib/l3kernel/l3file.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3flag.dtx b/macros/latex/contrib/l3kernel/l3flag.dtx
index 637da52ee7..278c71f27c 100644
--- a/macros/latex/contrib/l3kernel/l3flag.dtx
+++ b/macros/latex/contrib/l3kernel/l3flag.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-assign.dtx b/macros/latex/contrib/l3kernel/l3fp-assign.dtx
index da05eafa39..17d75d1045 100644
--- a/macros/latex/contrib/l3kernel/l3fp-assign.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-assign.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
% \maketitle
%
% \begin{documentation}
diff --git a/macros/latex/contrib/l3kernel/l3fp-aux.dtx b/macros/latex/contrib/l3kernel/l3fp-aux.dtx
index 3db65c9d29..ccd5e63ac1 100644
--- a/macros/latex/contrib/l3kernel/l3fp-aux.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-aux.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-basics.dtx b/macros/latex/contrib/l3kernel/l3fp-basics.dtx
index 3c5ad9195b..b79950c267 100644
--- a/macros/latex/contrib/l3kernel/l3fp-basics.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-basics.dtx
@@ -2,7 +2,7 @@
%
%% File: l3fp-basics.dtx
%
-% Copyright (C) 2011-2014,2016-2023 The LaTeX Project
+% Copyright (C) 2011-2023 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
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-convert.dtx b/macros/latex/contrib/l3kernel/l3fp-convert.dtx
index 835f9c4341..70983272dd 100644
--- a/macros/latex/contrib/l3kernel/l3fp-convert.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-convert.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-expo.dtx b/macros/latex/contrib/l3kernel/l3fp-expo.dtx
index 5ac216bf4c..f0e691f310 100644
--- a/macros/latex/contrib/l3kernel/l3fp-expo.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-expo.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-extended.dtx b/macros/latex/contrib/l3kernel/l3fp-extended.dtx
index b83b37335b..e374e7e288 100644
--- a/macros/latex/contrib/l3kernel/l3fp-extended.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-extended.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-functions.dtx b/macros/latex/contrib/l3kernel/l3fp-functions.dtx
new file mode 100644
index 0000000000..a899f3493a
--- /dev/null
+++ b/macros/latex/contrib/l3kernel/l3fp-functions.dtx
@@ -0,0 +1,282 @@
+% \iffalse
+%
+%% File l3fp-functions.dtx (C) Copyright 2012-2018,2020,2021,2023 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
+%
+% http://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]{l3doc}
+\usepackage{amsmath}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3fp-functions} package\\ Floating point functions^^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 2023-10-23}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3fp-functions} implementation}
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=fp>
+% \end{macrocode}
+%
+% \subsection{Declaring functions}
+%
+% \begin{macro}{\fp_new_function:n}
+% \begin{macro}{\@@_new_function:n}
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_new_function:n #1
+ { \exp_args:No \@@_new_function:n { \tl_to_str:n {#1} } }
+\cs_new_protected:Npn \@@_new_function:n #1
+ {
+ \@@_id_if_invalid:nTF {#1}
+ { \msg_error:nnn { fp } { invalid-identifier } {#1} }
+ {
+ \cs_if_exist:cT { @@_parse_word_#1:N }
+ {
+ \msg_error:nnn
+ { fp } { id-already-defined } {#1}
+ \cs_undefine:c { @@_parse_word_#1:N }
+ \cs_undefine:c { @@_#1_o:w }
+ }
+ \@@_function_set_parsing:Nn \cs_gset_eq:NN {#1}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+% {\@@_function_set_parsing:Nn, \@@_function_set_parsing_aux:NNn}
+% \begin{macrocode}
+\cs_new:Npn \@@_function_set_parsing:Nn #1#2
+ {
+ \exp_args:NNc \@@_function_set_parsing_aux:NNn #1
+ { @@_parse_word_#2:N } {#2}
+ }
+\cs_new:Npn \@@_function_set_parsing_aux:NNn #1#2#3
+ {
+ \cs_set:Npe \@@_tmp:w
+ {
+ \exp_not:N \@@_parse_function:NNN
+ \exp_not:N \@@_function_o:w
+ \exp_not:c { @@_#3_o:w }
+ }
+ \cs_if_eq:NNF #2 \@@_tmp:w
+ {
+ \cs_if_exist:NTF #2
+ {
+ \msg_warning:nnnn
+ { fp } { id-used-elsewhere } {#3} { function }
+ #1 #2 \@@_tmp:w
+ }
+ {
+ \cs_new_eq:NN #2 \scan_stop: % to declare the function
+ #1 #2 \@@_tmp:w
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_function_o:w}
+% \begin{macrocode}
+\cs_new:Npn \@@_function_o:w #1#2 @
+ {
+ \cs_if_exist:NTF #1
+ { #1 #2 @ }
+ {
+ \exp_after:wN \s_@@_symbolic
+ \exp_after:wN \@@_symbolic_chk:w
+ \exp_after:wN \@@_function_o:w
+ \exp_after:wN #1
+ \exp_after:wN ,
+ \exp_after:wN {
+ \exp:w \exp_end_continue_f:w
+ \@@_exp_after_array_f:w #2 \s_@@_expr_stop
+ \exp_after:wN
+ }
+ \exp_after:wN ;
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Defining functions by their expression}
+%
+% \begin{variable}{\l_@@_function_arg_int}
+% Labels the arguments of a function being defined.
+% \begin{macrocode}
+\int_new:N \l_@@_function_arg_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\fp_set_function:nnn}
+% \begin{macro}{\@@_set_function:Nnnn}
+% \begin{syntax}
+% \cs{fp_set_function:nnn} \Arg{identifier}
+% \Arg{comma-list of variables} \Arg{expression}
+% \end{syntax}
+% Defines the \meta{identifier} to stand for a function which expects
+% some arguments defined by the \meta{comma-list of variables}, and
+% evaluates to the \meta{expression}.
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_set_function:nnn #1
+ {
+ \exp_args:NNo \@@_set_function:Nnnn \cs_set_eq:cN
+ { \tl_to_str:n {#1} }
+ }
+\cs_new_protected:Npn \@@_set_function:Nnnn #1#2#3#4
+ {
+ \@@_id_if_invalid:nTF {#2}
+ { \msg_error:nnn { fp } { invalid-identifier } {#2} }
+ {
+ \cs_if_exist:cF { @@_parse_word_#2:N }
+ { \@@_function_set_parsing:Nn \cs_set_eq:NN {#2} }
+ \group_begin:
+ \int_zero:N \l_@@_function_arg_int
+ \exp_args:No \clist_map_inline:nn { \tl_to_str:n {#3} }
+ {
+ \int_incr:N \l_@@_function_arg_int
+ \exp_args:Ne \@@_clear_variable:n
+ { _ \tex_romannumeral:D \l_@@_function_arg_int }
+ \fp_clear_variable:n {##1}
+ \cs_set_nopar:cpe { l_@@_variable_##1_fp }
+ {
+ \exp_not:N \s__fp_symbolic
+ \exp_not:N \@@_symbolic_chk:w
+ \exp_not:N \@@_function_arg_o:w
+ \int_use:N \l_@@_function_arg_int
+ ########1 , { } ;
+ }
+ }
+ \cs_set:Npn \@@_function_arg_o:w ##1 @
+ {
+ \exp_after:wN \s_@@_symbolic
+ \exp_after:wN \@@_symbolic_chk:w
+ \exp_after:wN \@@_function_arg_o:w
+ \tex_romannumeral:D
+ \@@_exp_after_symbolic_loop:N ##1
+ { , \tex_romannumeral:D \use_none:nn }
+ \exp_after:wN \c_zero_int
+ \exp_after:wN { \exp_after:wN } \exp_after:wN ;
+ }
+ \fp_set:Nn \l_@@_symbolic_fp {#4}
+ \use:e
+ {
+ \exp_not:n { \cs_gset:Npn \@@_tmp:w ##1 }
+ { \exp_not:o { \l_@@_symbolic_fp } }
+ }
+ \use:e
+ {
+ \exp_not:n { \cs_gset:Npn \@@_tmp:w ##1 @ }
+ {
+ \exp_not:N \@@_exp_after_symbolic_f:nw
+ \exp_not:n { { \exp_after:wN \exp_stop_f: } }
+ \exp_not:o { \@@_tmp:w { . , {##1} } }
+ }
+ }
+ \group_end:
+ #1 { @@_#2_o:w } \@@_tmp:w
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {
+% \@@_function_arg_o:w,
+% \@@_function_arg_few:w,
+% \@@_function_arg_get:w
+% }
+% \begin{macrocode}
+\cs_new:Npn \@@_function_arg_o:w #1. #2
+ {
+ \if_meaning:w @ #2
+ \exp_after:wN \@@_function_arg_few:w
+ \fi:
+ \if_int_compare:w #1 = \c_one_int
+ \exp_after:wN \@@_function_arg_get:w
+ \fi:
+ \@@_use_i_until_s:nw
+ {
+ \exp_after:wN \@@_function_arg_o:w
+ \int_value:w \int_eval:n { #1 - 1 } .
+ }
+ #2
+ }
+\cs_new:Npn \@@_function_arg_few:w #1 @ { \exp_after:wN \c_nan_fp }
+\cs_new:Npn \@@_function_arg_get:w #1#2#3; #4 @
+ {
+ \@@_exp_after_array_f:w #3; \s_@@_expr_stop
+ \exp_after:wN \exp_stop_f:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\fp_clear_function:n}
+% \begin{macro}{\@@_clear_function:n}
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_clear_function:n #1
+ { \exp_args:No \@@_clear_function:n { \tl_to_str:n {#1} } }
+\cs_new_protected:Npn \@@_clear_function:n #1
+ {
+ \cs_undefine:c { @@_parse_word_ #1 :N }
+ \@@_function_set_parsing:Nn \cs_set_eq:NN {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% ^^A todo: add check for number of args
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/macros/latex/contrib/l3kernel/l3fp-logic.dtx b/macros/latex/contrib/l3kernel/l3fp-logic.dtx
index 2f439c2925..5e98d6b62c 100644
--- a/macros/latex/contrib/l3kernel/l3fp-logic.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-logic.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -163,7 +163,7 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_compare_back_any:ww, \@@_compare_back:ww, \@@_compare_nan:w}
+% \begin{macro}[EXP]{\@@_compare_back:ww, \@@_bcmp:ww, \@@_compare_back_any:ww, \@@_compare_nan:w}
% \begin{quote}
% \cs{@@_compare_back_any:ww} \meta{y} |;| \meta{x} |;|
% \end{quote}
@@ -178,6 +178,17 @@
% a different type, the highest type is a larger number. Finally, if
% $y\leq 0$, then $x>y$, unless both are zero.
% \begin{macrocode}
+\cs_new:Npn \@@_compare_back:ww #1#2; #3#4;
+ {
+ \cs:w
+ @@
+ \@@_type_from_scan:N #1
+ _bcmp
+ \@@_type_from_scan:N #3
+ :ww
+ \cs_end:
+ #1#2; #3#4;
+ }
\cs_new:Npn \@@_compare_back_any:ww #1#2; #3
{
\@@_if_type_fp:NTwFw
@@ -195,7 +206,7 @@
}
#1#2 ; #3
}
-\cs_new:Npn \@@_compare_back:ww
+\cs_new:Npn \@@_bcmp:ww
\s_@@ \@@_chk:w #1 #2 #3;
\s_@@ \@@_chk:w #4 #5 #6;
{
diff --git a/macros/latex/contrib/l3kernel/l3fp-parse.dtx b/macros/latex/contrib/l3kernel/l3fp-parse.dtx
index 418974d826..58fc4f1f2a 100644
--- a/macros/latex/contrib/l3kernel/l3fp-parse.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-parse.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-random.dtx b/macros/latex/contrib/l3kernel/l3fp-random.dtx
index 3e3b5cfdfc..3cff0bdc1a 100644
--- a/macros/latex/contrib/l3kernel/l3fp-random.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-random.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-round.dtx b/macros/latex/contrib/l3kernel/l3fp-round.dtx
index f0853f5999..901cb5ba34 100644
--- a/macros/latex/contrib/l3kernel/l3fp-round.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-round.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-symbolic.dtx b/macros/latex/contrib/l3kernel/l3fp-symbolic.dtx
new file mode 100644
index 0000000000..277ecfabf5
--- /dev/null
+++ b/macros/latex/contrib/l3kernel/l3fp-symbolic.dtx
@@ -0,0 +1,673 @@
+% \iffalse
+%
+%% File l3fp-symbolic.dtx (C) Copyright 2012-2015,2017,2018,2020,2021,2023 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
+%
+% http://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]{l3doc}
+\usepackage{amsmath}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3fp-symbolic} package\\ Symbolic expressions^^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 2023-10-23}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3fp-symbolic} implementation}
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=fp>
+% \end{macrocode}
+%
+% \subsection{Misc}
+%
+% \begin{variable}{\l_@@_symbolic_fp}
+% Scratch floating point.
+% \begin{macrocode}
+\fp_new:N \l_@@_symbolic_fp
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Building blocks for expressions}
+%
+% Every symbolic expression has the form \cs{s_@@_symbolic}
+% \cs{@@_symbolic_chk:w} \meta{operation} |,| \Arg{operands} \meta{junk}
+% |;| where the \meta{operation} is a list of \texttt{N}-type tokens,
+% the \meta{operands} is an array of floating point objects, and the
+% \meta{junk} is to be discarded. If the outermost operator (last to be
+% evaluated) is unary, the expression has the form
+% \begin{quote}
+% \cs{s_@@_symbolic} \cs{@@_symbolic_chk:w} \\
+% \cs{@@_types_unary:NNw} |\__fp_|\meta{op}|_o:w| \meta{token} |,| \\
+% |{| \meta{operand} |}| \meta{junk} |;|
+% \end{quote}
+% where the \meta{op} is a unary operation (|set_sign|, |cos|,
+% \ldots{}), and the \meta{token} and \meta{operand} are used as
+% arguments for \cs{@@_\meta{op}_o:w} (or the type-specific analog of
+% this function). If the outermost operator is binary, the expression
+% has the form
+% \begin{quote}
+% \cs{s_@@_symbolic} \cs{@@_symbolic_chk:w} \\
+% \cs{@@_types_binary:Nww} |\__fp_|\meta{op}|_o:ww| |,| \\
+% |{| \meta{operand_1} \meta{operand_2} |}| \meta{junk} |;|
+% \end{quote}
+% where the \meta{op} is an operation (|+|, |&|, \ldots{}), and
+% |\__fp_|\meta{op}|_o:ww| receives the \meta{operands} as arguments.
+% If the expression consists of a single variable, it is stored as
+% \begin{quote}
+% \cs{s_@@_symbolic} \cs{@@_symbolic_chk:w} \\
+% \cs{@@_variable_o:w} \meta{identifier} |,| \\
+% |{| |}| \meta{junk} |;|
+% \end{quote}
+%
+% Symbolic expressions are stored in a prefix form. When encountering a
+% symbolic expression in a floating point computation, we attempt to
+% evaluate the operands as much as possible, and if that yields floating
+% point numbers rather than expressions, we apply the operator which
+% follows (if the function is known).
+%
+% For instance, the expression |a + b * sin(c)| is stored as
+% \begin{verbatim}
+% \s__fp_symbolic \__fp_symbolic_chk:w
+% \__fp_types_binary:Nww \__fp_+_o:ww ,
+% {
+% \s__fp_symbolic \__fp_symbolic_chk:w
+% \__fp_variable_o:w a , { } ;
+% \s__fp_symbolic \__fp_symbolic_chk:w
+% \__fp_types_binary:Nww \__fp_*_o:ww ,
+% {
+% \s__fp_symbolic \__fp_symbolic_chk:w
+% \__fp_variable_o:w b , { } ;
+% \s__fp_symbolic \__fp_symbolic_chk:w
+% \__fp_types_unary:NNw \__fp_sin_o:w \use_i:nn ,
+% {
+% \s__fp_symbolic \__fp_symbolic_chk:w
+% \__fp_variable_o:w c , { } ;
+% } ;
+% } ;
+% } ;
+% \end{verbatim}
+%
+% \begin{variable}{\s_@@_symbolic}
+% Scan mark indicating the start of a symbolic expression.
+% \begin{macrocode}
+\scan_new:N \s_@@_symbolic
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_symbolic_chk:w}
+% Analog of \cs{@@_chk:w} for symbolic expressions.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_symbolic_chk:w #1,#2#3;
+ {
+ \msg_error:nne { fp } { misused-fp }
+ {
+ \@@_to_tl_dispatch:w
+ \s_@@_symbolic \@@_symbolic_chk:w #1,{#2};
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Expanding after a symbolic expression}
+%
+% \begin{macro}[EXP]
+% {\@@_if_has_symbolic:nTF, \@@_if_has_symbolic_aux:w}
+% Tests if |#1| contains \cs{s_@@_symbolic} at top-level. This test
+% should be precise enough to determine if a given an array contains a
+% symbolic expression or only consists in floating points. Used in
+% \cs{@@_exp_after_symbolic_f:nw}.
+% \begin{macrocode}
+\cs_new:Npn \@@_if_has_symbolic:nTF #1
+ {
+ \@@_if_has_symbolic_aux:w
+ #1 \s_@@_mark \use_i:nn
+ \s_@@_symbolic \s_@@_mark \use_ii:nn
+ \s_@@_stop
+ }
+\cs_new:Npn \@@_if_has_symbolic_aux:w
+ #1 \s_@@_symbolic #2 \s_@@_mark #3#4 \s_@@_stop { #3 }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_exp_after_symbolic_f:nw}
+% \begin{macro}[EXP]
+% {\@@_exp_after_symbolic_aux:w, \@@_exp_after_symbolic_loop:N}
+% This function does two things: trigger an \texttt{f}-expansion of
+% the argument~|#1| after the following symbolic expression, and
+% evaluate all pieces of the expression which can be evaluated.
+% \begin{macrocode}
+\cs_new:Npn \@@_exp_after_symbolic_f:nw
+ #1 \s_@@_symbolic \@@_symbolic_chk:w #2, #3#4;
+ {
+ \exp_after:wN \@@_exp_after_symbolic_aux:w
+ \exp:w
+ \@@_exp_after_symbolic_loop:N #2
+ { , \exp:w \use_none:nn }
+ \exp_after:wN \exp_end: \exp_after:wN
+ {
+ \exp:w \exp_end_continue_f:w
+ \@@_exp_after_array_f:w #3 \s_@@_expr_stop
+ \exp_after:wN
+ }
+ \exp_after:wN ;
+ \exp:w \exp_end_continue_f:w #1
+ }
+\cs_new:Npn \@@_exp_after_symbolic_aux:w #1, #2;
+ {
+ \@@_if_has_symbolic:nTF {#2}
+ { \s_@@_symbolic \@@_symbolic_chk:w #1, {#2} ; }
+ { #1 #2 @ \prg_do_nothing: }
+ }
+\cs_new:Npn \@@_exp_after_symbolic_loop:N #1
+ {
+ \exp_after:wN \exp_end:
+ \exp_after:wN #1
+ \exp:w
+ \@@_exp_after_symbolic_loop:N
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Applying infix operators to expressions}
+%
+% \begin{macro}[EXP]{\@@_symbolic_binary_o:Nww}
+% Used when applying infix operators to expressions.
+% \begin{macrocode}
+\cs_new:Npn \@@_symbolic_binary_o:Nww #1 #2; #3;
+ {
+ \@@_exp_after_symbolic_f:nw { \exp_after:wN \exp_stop_f: }
+ \s_@@_symbolic \@@_symbolic_chk:w
+ \@@_types_binary:Nww #1 , { #2; #3; } ;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{@makeother}{^} %^^A Hack!
+% \begin{@makeother}{|} %^^A Hack!
+% \begin{@makeother}{&} %^^A Hack!
+% \begin{macro}[EXP]
+% {
+% \@@_symbolic_+_symbolic_o:ww,
+% \@@_symbolic_+_o:ww,
+% \@@_+_symbolic_o:ww,
+% \@@_symbolic_-_symbolic_o:ww,
+% \@@_symbolic_-_o:ww,
+% \@@_-_symbolic_o:ww,
+% \@@_symbolic_*_symbolic_o:ww,
+% \@@_symbolic_*_o:ww,
+% \@@_*_symbolic_o:ww,
+% \@@_symbolic_/_symbolic_o:ww,
+% \@@_symbolic_/_o:ww,
+% \@@_/_symbolic_o:ww,
+% \@@_symbolic_^_symbolic_o:ww,
+% \@@_symbolic_^_o:ww,
+% \@@_^_symbolic_o:ww,
+% \@@_symbolic_|_symbolic_o:ww,
+% \@@_symbolic_|_o:ww,
+% \@@_|_symbolic_o:ww,
+% \@@_symbolic_&_symbolic_o:ww,
+% \@@_symbolic_&_o:ww,
+% \@@_&_symbolic_o:ww,
+% }
+% \begin{macrocode}
+\cs_set:Npn \@@_tmp:w #1#2
+ {
+ \cs_new_nopar:cpn
+ { @@_symbolic_#2_symbolic_o:ww }
+ { \@@_symbolic_binary_o:Nww #1 }
+ \cs_new_eq:cc
+ { @@_symbolic_#2 _o:ww }
+ { @@_symbolic_#2_symbolic_o:ww }
+ \cs_new_eq:cc
+ { @@ _#2_symbolic_o:ww }
+ { @@_symbolic_#2_symbolic_o:ww }
+ }
+\tl_map_inline:nn { + - * / ^ & | }
+ { \exp_args:Nc \@@_tmp:w { @@_#1_o:ww } {#1} }
+% \end{macrocode}
+% \end{macro}
+% \end{@makeother}
+% \end{@makeother}
+% \end{@makeother}
+%
+% \subsection{Applying prefix functions to expressions}
+%
+% \begin{macro}[aux, EXP]{\@@_symbolic_unary_o:NNw}
+% Used when applying infix operators to expressions.
+% \begin{macrocode}
+\cs_new:Npn \@@_symbolic_unary_o:NNw #1#2#3; @
+ {
+ \@@_exp_after_symbolic_f:nw { \exp_after:wN \exp_stop_f: }
+ \s_@@_symbolic \@@_symbolic_chk:w
+ \@@_types_unary:NNw #1#2 , { #3; } ;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {
+% \@@_symbolic_acos_o:w ,
+% \@@_symbolic_acsc_o:w ,
+% \@@_symbolic_asec_o:w ,
+% \@@_symbolic_asin_o:w ,
+% \@@_symbolic_cos_o:w ,
+% \@@_symbolic_cot_o:w ,
+% \@@_symbolic_csc_o:w ,
+% \@@_symbolic_exp_o:w ,
+% \@@_symbolic_ln_o:w ,
+% \@@_symbolic_not_o:w ,
+% \@@_symbolic_sec_o:w ,
+% \@@_symbolic_set_sign_o:w ,
+% \@@_symbolic_sin_o:w ,
+% \@@_symbolic_tan_o:w ,
+% }
+% \begin{macrocode}
+\tl_map_inline:nn
+ {
+ {acos} {acsc} {asec} {asin} {cos} {cot} {csc} {exp} {ln}
+ {not} {sec} {set_sign} {sin} {sqrt} {tan}
+ }
+ {
+ \cs_new_nopar:cpe { @@_symbolic_#1_o:w }
+ {
+ \exp_not:N \@@_symbolic_unary_o:NNw
+ \exp_not:c { @@_#1_o:w }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Conversions}
+%
+% \begin{macro}[EXP]
+% {
+% \@@_symbolic_to_decimal:w,
+% \@@_symbolic_to_int:w,
+% \@@_symbolic_to_scientific:w
+% }
+% \begin{macro}[EXP]{\@@_symbolic_convert:wnnN}
+% Symbolic expressions cannot be converted to decimal, integer, or
+% scientific notation unless they can be reduced to
+% \begin{macrocode}
+\cs_set_protected:Npn \@@_tmp:w #1#2#3
+ {
+ \cs_new_nopar:cpn { @@_symbolic_to_#1:w }
+ {
+ \exp_after:wN \@@_symbolic_convert:wnnN
+ \exp:w \exp_end_continue_f:w
+ \@@_exp_after_symbolic_f:nw { { #2 } { fp_to_#1 } #3 }
+ }
+ }
+\@@_tmp:w { decimal } { 0 } \@@_to_decimal_dispatch:w
+\@@_tmp:w { int } { 0 } \@@_to_int_dispatch:w
+\@@_tmp:w { scientific } { nan } \@@_to_scientific_dispatch:w
+\cs_new:Npn \@@_symbolic_convert:wnnN #1#2; #3#4#5
+ {
+ \str_if_eq:nnTF {#1} { \s_@@_symbolic }
+ { \@@_invalid_operation:nnw {#3} {#4} #1#2; }
+ { #5 #1#2; }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {\@@_symbolic_cs_arg_to_fn:NN, \@@_symbolic_op_arg_to_fn:nN}
+% \begin{macrocode}
+\cs_new:Npn \@@_symbolic_cs_arg_to_fn:NN #1
+ {
+ \exp_args:Nf \@@_symbolic_op_arg_to_fn:nN
+ { \@@_types_cs_to_op:N #1 }
+ }
+\cs_new:Npn \@@_symbolic_op_arg_to_fn:nN #1#2
+ {
+ \str_case:nnF { #1 #2 }
+ {
+ { not ? } { ! }
+ { set_sign 0 } { abs }
+ { set_sign 2 } { - }
+ }
+ {
+ \token_if_eq_meaning:NNTF #2 \use_ii:nn
+ { #1 d } {#1}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_symbolic_to_tl:w}
+% \begin{macro}[rEXP]
+% {
+% \@@_symbolic_unary_to_tl:NNw,
+% \@@_symbolic_binary_to_tl:Nww
+% }
+% Converting a symbolic expression to a token list is possible.
+% \begin{macrocode}
+\cs_new:Npn \@@_symbolic_to_tl:w
+ \s_@@_symbolic \@@_symbolic_chk:w #1#2, #3#4;
+ {
+ \str_case:nnTF {#1}
+ {
+ { \@@_types_unary:NNw } { \@@_symbolic_unary_to_tl:NNw }
+ { \@@_types_binary:Nww } { \@@_symbolic_binary_to_tl:Nww }
+ { \@@_function_o:w } { \@@_symbolic_function_to_tl:Nw }
+ }
+ { #2, #3 @ }
+ { \tl_to_str:n {#2} }
+ }
+\cs_new:Npn \@@_symbolic_unary_to_tl:NNw #1#2 , #3 @
+ {
+ \use:e
+ {
+ \@@_symbolic_cs_arg_to_fn:NN #1#2
+ ( \@@_to_tl_dispatch:w #3 )
+ }
+ }
+\cs_new:Npn \@@_symbolic_binary_to_tl:Nww #1, #2; #3; @
+ {
+ \use:e
+ {
+ ( \@@_to_tl_dispatch:w #2; )
+ \@@_types_cs_to_op:N #1
+ ( \@@_to_tl_dispatch:w #3; )
+ }
+ }
+\cs_new:Npn \@@_symbolic_function_to_tl:Nw #1, #2@
+ {
+ \use:e
+ {
+ \@@_types_cs_to_op:N #1
+ ( \@@_array_to_clist:n {#2} )
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Identifiers}
+%
+% Functions defined here are not necessarily tied to symbolic
+% expressions.
+%
+% \begin{macro}[TF]{\@@_id_if_invalid:n}
+% \begin{macro}[EXP]{\@@_id_if_invalid_aux:N}
+% If |#1| contains a space, it is not a valid identifier. Otherwise,
+% loop through letters in |#1|: if it is not a letter, break the loop
+% and return \texttt{true}. If the end of the loop is reached
+% without finding any non-letter, return \texttt{false}.
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn
+ \@@_id_if_invalid:n #1 { T , F , TF }
+ {
+ \tl_if_empty:nTF {#1}
+ { \prg_return_true: }
+ {
+ \tl_if_in:onTF { \tl_to_str:n {#1} } { ~ }
+ { \prg_return_true: }
+ {
+ \exp_after:wN \@@_id_if_invalid_aux:N \tl_to_str:n {#1}
+ { ? \prg_break:n \prg_return_false: }
+ \prg_break_point:
+ }
+ }
+ }
+\cs_new:Npn \@@_id_if_invalid_aux:N #1
+ {
+ \use_none:n #1
+ \int_compare:nF { `a <= `#1 <= `z }
+ {
+ \int_compare:nF { `A <= `#1 <= `Z }
+ { \prg_break:n \prg_return_true: }
+ }
+ \@@_id_if_invalid_aux:N
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Declaring variables and assigning values}
+%
+% \begin{macro}[EXP]{\@@_variable_o:w}
+% We do not use \cs{exp_last_unbraced:Nv} to extract the value of
+% |\l__fp_variable_#1_fp| because in \cs{fp_set_variable:nn} we define
+% this \texttt{fp} variable to be something which \texttt{f}-expands
+% to an actual floating point, rather than a genuine floating point.
+% \begin{macrocode}
+\cs_new:Npn \@@_variable_o:w #1 @ #2
+ {
+ \fp_if_exist:cTF { l_@@_variable_#1_fp }
+ {
+ \exp_last_unbraced:Nf \@@_exp_after_array_f:w
+ { \use:c { l_@@_variable_#1_fp } } \s_@@_expr_stop
+ \exp_after:wN \exp_stop_f: #2
+ }
+ {
+ \token_if_eq_meaning:NNTF #2 \prg_do_nothing:
+ {
+ \s_@@_symbolic \@@_symbolic_chk:w
+ \@@_variable_o:w #1 , { } ;
+ }
+ {
+ \exp_after:wN \s_@@_symbolic
+ \exp_after:wN \@@_symbolic_chk:w
+ \exp_after:wN \@@_variable_o:w
+ \exp:w
+ \@@_exp_after_symbolic_loop:N #1
+ { , \exp:w \use_none:nn }
+ \exp_after:wN \exp_end:
+ \exp_after:wN { \exp_after:wN } \exp_after:wN ;
+ #2
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {\@@_variable_set_parsing:Nn, \@@_variable_set_parsing_aux:NNn}
+% \begin{macrocode}
+\cs_new:Npn \@@_variable_set_parsing:Nn #1#2
+ {
+ \cs_set_nopar:Npn \@@_tmp:w
+ {
+ \@@_exp_after_symbolic_f:nw { \@@_parse_infix:NN }
+ \s_@@_symbolic \@@_symbolic_chk:w
+ \@@_variable_o:w #2 , { } ;
+ }
+ \exp_args:NNc \@@_variable_set_parsing_aux:NNn #1
+ { @@_parse_word_#2:N } {#2}
+ }
+\cs_new:Npn \@@_variable_set_parsing_aux:NNn #1#2#3
+ {
+ \cs_if_eq:NNF #2 \@@_tmp:w
+ {
+ \cs_if_exist:NTF #2
+ {
+ \msg_warning:nnnn
+ { fp } { id-used-elsewhere } {#3} { variable }
+ #1 #2 \@@_tmp:w
+ }
+ {
+ \cs_new_eq:NN #2 \scan_stop: % to declare the function
+ #1 #2 \@@_tmp:w
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\fp_clear_variable:n}
+% \begin{macro}{\@@_clear_variable:n}
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_clear_variable:n #1
+ {
+ \@@_id_if_invalid:nTF {#1}
+ { \msg_error:nnn { fp } { id-invalid } {#1} }
+ { \exp_args:No \@@_clear_variable:n { \tl_to_str:n {#1} } }
+ }
+\cs_new_protected:Npn \@@_clear_variable:n #1
+ {
+ \cs_undefine:c { l_@@_variable_#1_fp }
+ \@@_variable_set_parsing:Nn \cs_set_eq:NN {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\fp_new_variable:n}
+% \begin{macro}{\@@_new_variable:n}
+% Check that |#1| is a valid identifier. If the identifier is already
+% in use, complain. Then set |\__fp_parse_word_#1:N| to use
+% |\__fp_variable_o:w|.
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_new_variable:n #1
+ {
+ \@@_id_if_invalid:nTF {#1}
+ { \msg_error:nnn { fp } { id-invalid } {#1} }
+ { \exp_args:No \@@_new_variable:n { \tl_to_str:n {#1} } }
+ }
+\cs_new_protected:Npn \@@_new_variable:n #1
+ {
+ \cs_if_exist:cT { @@_parse_word_#1:N }
+ {
+ \msg_error:nnn
+ { fp } { id-already-defined } {#1}
+ \cs_undefine:c { @@_parse_word_#1:N }
+ \cs_undefine:c { l_@@_variable_#1_fp }
+ }
+ \@@_variable_set_parsing:Nn \cs_gset_eq:NN {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\fp_set_variable:nn}
+% \begin{macro}{\@@_set_variable:nn}
+% Refuse invalid identifiers. If the variable does not exist yet,
+% define it just as in \cs{fp_new_variable:n} (but without unnecessary
+% checks). Then evaluate~|#2|. If the result contains the
+% identifier~|#1|, we would later get a loop in cases such as
+% \begin{quote}
+% \cs{fp_set_variable:nn} |{A}| |{A}|\\
+% \cs{fp_show:n} |{A}|
+% \end{quote}
+% To detect this, define |\l__fp_variable_#1_fp| to raise an
+% internal flag and evaluate to \texttt{nan}. Then re-evaluate
+% \cs{l_@@_symbolic_fp}, and store the result in~|#1|. If the flag is
+% raised, |#1|~was present in \cs{l_@@_symbolic_fp}. In all cases,
+% the |#1|-free result ends up in |\l__fp_variable_#1_fp|.
+% \begin{macrocode}
+\flag_new:n { @@_symbolic }
+\cs_new_protected:Npn \fp_set_variable:nn #1
+ {
+ \@@_id_if_invalid:nTF {#1}
+ { \msg_error:nnn { fp } { id-invalid } {#1} }
+ { \exp_args:No \@@_set_variable:nn { \tl_to_str:n {#1} } }
+ }
+\cs_new_protected:Npn \@@_set_variable:nn #1#2
+ {
+ \@@_variable_set_parsing:Nn \cs_set_eq:NN {#1}
+ \fp_set:Nn \l_@@_symbolic_fp {#2}
+ \cs_set_nopar:cpn { l_@@_variable_#1_fp }
+ { \flag_ensure_raised:n { @@_symbolic } \c_nan_fp }
+ \flag_clear:n { @@_symbolic }
+ \fp_set:cn { l_@@_variable_#1_fp } { \l_@@_symbolic_fp }
+ \flag_if_raised:nT { @@_symbolic }
+ {
+ \msg_error:nneee { fp } { id-loop }
+ { \tl_to_str:n {#1} }
+ { \tl_to_str:n {#2} }
+ { \fp_to_tl:N \l_@@_symbolic_fp }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Messages}
+%
+% \begin{macrocode}
+\msg_new:nnnn { fp } { id-invalid }
+ { Floating~point~identifier~'#1'~invalid. }
+ {
+ LaTeX~has~been~asked~to~create~a~new~floating~point~identifier~'#1'~
+ but~this~may~only~contain~ASCII~letters.
+ }
+\msg_new:nnnn { fp } { id-already-defined }
+ { Floating~point~identifier~'#1'~already~defined. }
+ {
+ LaTeX~has~been~asked~to~create~a~new~floating~point~identifier~'#1'~
+ but~this~name~has~already~been~used~elsewhere.
+ }
+\msg_new:nnnn { fp } { id-used-elsewhere }
+ { Floating~point~identifier~'#1'~already~used~for~something~else. }
+ {
+ LaTeX~has~been~asked~to~create~a~new~floating~point~identifier~'#1'~
+ but~this~name~is~used,~and~is~not~a~user-defined~#2.
+ }
+\msg_new:nnnn { fp } { id-loop }
+ { Variable~'#1'~used~in~the~definition~of~'#1'. }
+ {
+ LaTeX~has~been~asked~to~set~the~floating~point~identifier~'#1'~
+ to~the~expression~'#2'.~Evaluating~this~expression~yields~'#3',~
+ which~contains~'#1'~itself.
+ }
+% \end{macrocode}
+%
+% \subsection{Road-map}
+%
+% The following functions are not implemented: |min|, |max|, |?:|,
+% comparisons, |round|, |atan|, |acot|.
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/macros/latex/contrib/l3kernel/l3fp-traps.dtx b/macros/latex/contrib/l3kernel/l3fp-traps.dtx
index 674ecdfd2d..1bdece9ba7 100644
--- a/macros/latex/contrib/l3kernel/l3fp-traps.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-traps.dtx
@@ -2,7 +2,7 @@
%
%% File: l3fp-traps.dtx
%
-% Copyright (C) 2011-2014,2016-2023 The LaTeX Project
+% Copyright (C) 2011-2023 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
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
% \maketitle
%
% \begin{documentation}
diff --git a/macros/latex/contrib/l3kernel/l3fp-trig.dtx b/macros/latex/contrib/l3kernel/l3fp-trig.dtx
index b7bc6c19ce..c49383a178 100644
--- a/macros/latex/contrib/l3kernel/l3fp-trig.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-trig.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-types.dtx b/macros/latex/contrib/l3kernel/l3fp-types.dtx
new file mode 100644
index 0000000000..693cec5ccc
--- /dev/null
+++ b/macros/latex/contrib/l3kernel/l3fp-types.dtx
@@ -0,0 +1,184 @@
+% \iffalse
+%
+%% File l3fp-types.dtx (C) Copyright 2012-2015,2017,2018,2020,2021,2023 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
+%
+% http://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]{l3doc}
+\usepackage{amsmath}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3fp-types} package\\ Floating point types^^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 2023-10-23}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3fp-types} implementation}
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=fp>
+% \end{macrocode}
+%
+% \subsection{Support for types}
+%
+% Despite lack of documentation, the \pkg{l3fp} internals support types.
+% Each additional type must define
+% \begin{itemize}
+% \item |\s__fp_|\meta{type} and |\__fp_|\meta{type}|_chk:w|;
+% \item |\__fp_exp_after_|\meta{type}|_f:nw|;
+% \item |\__fp_|\meta{type}|_to_|\meta{out}|:w| for \meta{out} among
+% |decimal|, |scientific|, |tl|;
+% \end{itemize}
+% and may define
+% \begin{itemize}
+% \item |\__fp_|\meta{type}|_to_int:w| and |\__fp_|\meta{type}|_to_dim:w|;
+% \item |\__fp_|\meta{op}|_|\meta{type}|_o:w| for any of the \meta{op}
+% that the type implements, among |acos|, |acsc|, |asec|, |asin|,
+% |cos|, |cot|, |csc|, |exp|, |ln|, |not|, |sec|, |set_sign|, |sin|,
+% |tan|;
+% \item |\__fp_|\meta{type_1}|_|\meta{op}|_|\meta{type_2}|_o:ww| for
+% \meta{op} among |^*/-+&|\verb"|" and for every pair of types;
+% \item |\__fp_|\meta{type_1}|_bcmp_|\meta{type_2}|:ww| for every
+% pair of types.
+% \end{itemize}
+% The latter is set up in \pkg{l3fp-logic}.
+%
+% \subsection{Dispatch according to the type}
+%
+% \begin{macro}[EXP]
+% {\@@_types_cs_to_op:N, \@@_types_cs_to_op_auxi:wwwn}
+% From |\__fp_|\meta{op}|_o:w| produce \meta{op}, otherwise~|?|.
+% \begin{macrocode}
+\cs_new:Npe \@@_types_cs_to_op:N #1
+ {
+ \exp_not:N \exp_after:wN \exp_not:N \@@_types_cs_to_op_auxi:wwwn
+ \exp_not:N \token_to_str:N #1 \s_@@_mark
+ \exp_not:N \@@_use_i_delimit_by_s_stop:nw
+ \tl_to_str:n { @@_ _o:w } \s_@@_mark
+ { \exp_not:N \@@_use_i_delimit_by_s_stop:nw ? }
+ \s_@@_stop
+ }
+\use:e
+ {
+ \cs_new:Npn \exp_not:N \@@_types_cs_to_op_auxi:wwwn
+ #1 \tl_to_str:n { @@_ } #2
+ \tl_to_str:n { _o:w } #3 \s_@@_mark #4 { #4 {#2} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_types_unary:NNw}
+% \begin{macro}[EXP]
+% {\@@_types_unary_auxi:nNw, \@@_types_unary_auxii:NnNw}
+% \begin{syntax}
+% \cs{@@_types_unary:NNw} |\__fp_|\meta{function}|_o:w|
+% ~~\meta{token} \meta{operand} |@|
+% \end{syntax}
+% \begin{macrocode}
+\cs_new:Npn \@@_types_unary:NNw #1
+ {
+ \exp_args:Nf \@@_types_unary_auxi:nNw
+ { \@@_types_cs_to_op:N #1 }
+ }
+\cs_new:Npn \@@_types_unary_auxi:nNw #1#2#3
+ {
+ \exp_after:wN \@@_types_unary_auxii:NnNw
+ \cs:w @@_#1 \@@_type_from_scan:N #3 _o:w \cs_end:
+ {#1}
+ #2#3
+ }
+\cs_new:Npn \@@_types_unary_auxii:NnNw #1#2#3
+ {
+ \token_if_eq_meaning:NNTF \scan_stop: #1
+ { \@@_invalid_operation_o:nw {#2} }
+ { #1 #3 }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_types_binary:Nww}
+% \begin{macro}[EXP]
+% {\@@_types_binary_auxi:Nww, \@@_types_binary_auxii:NNww}
+% \begin{syntax}
+% \cs{@@_types_binary:Nww} |\__fp_|\meta{binop}|_o:ww|
+% ~~\meta{operand_1} \meta{operand_2} |@|
+% \end{syntax}
+% \begin{macrocode}
+\cs_new:Npn \@@_types_binary:Nww #1
+ {
+ \exp_last_unbraced:Nf \@@_types_binary_auxi:Nww
+ { \@@_types_cs_to_op:N #1 }
+ }
+\cs_new:Npn \@@_types_binary_auxi:Nww #1#2#3; #4#5; @
+ {
+ \exp_after:wN \@@_types_binary_auxii:NNww
+ \cs:w
+ @@
+ \@@_type_from_scan:N #2
+ _#1
+ \@@_type_from_scan:N #4
+ _o:ww
+ \cs_end:
+ #1 #2#3; #4#5;
+ }
+\cs_new:Npn \@@_types_binary_auxii:NNww #1#2
+ {
+ \token_if_eq_meaning:NNTF \scan_stop: #1
+ { \@@_invalid_operation_o:Nww #2 }
+ {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/macros/latex/contrib/l3kernel/l3fp.dtx b/macros/latex/contrib/l3kernel/l3fp.dtx
index 60a7b7534f..578d568978 100644
--- a/macros/latex/contrib/l3kernel/l3fp.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp.dtx
@@ -49,7 +49,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -658,6 +658,138 @@
% the \meta{code} should make use of the \meta{tl~var}.
% \end{function}
%
+% \section{Symbolic expressions}
+%
+% Floating point expressions support variables: these can only be set locally,
+% so act like standard \cs[no-index]{l_\dots} variables.
+% \begin{quote}\let\obeyedline=\newline\obeylines^^A
+% \cs{fp_new_variable:n} |{ A }|
+% \cs{fp_set:Nn} \cs{l_tmpb_fp} |{ 1 * sin(A) + 3**2 }|
+% \cs{fp_show:n} |{| \cs{l_tmpb_fp} |}|
+% \cs{fp_show:N} \cs{l_tmpb_fp}
+% \cs{fp_set_variable:nn} |{ A }| |{ pi/2 }|
+% \cs{fp_show:n} |{| \cs{l_tmpb_fp} |}|
+% \cs{fp_show:N} \cs{l_tmpb_fp}
+% \cs{fp_set_variable:nn} |{ A }| |{ 0 }|
+% \cs{fp_show:n} |{| \cs{l_tmpb_fp} |}|
+% \cs{fp_show:N} \cs{l_tmpb_fp}
+% \end{quote}
+% defines~|A| to be a variable, then defines \cs{l_tmpb_fp} to stand for
+% |1*sin(A)+9| (note that |3**2| is evaluated, but the |1*|~product is
+% not simplified away). Until \cs{l_tmpb_fp} is changed, \cs{fp_show:N}
+% \cs{l_tmpb_fp} will show |((1*sin(A))+9)| regardless of the value
+% of~|A|. The next step defines~|A| to be equal to~|pi/2|: then
+% \cs{fp_show:n} |{| \cs{l_tmpb_fp} |}| will evaluate \cs{l_tmpb_fp} and
+% show~|10|. We then redefine~|A| to be~|0|: since \cs{l_tmpb_fp} still
+% stands for |1*sin(A)+9|, the value shown is then~|9|. Variables can
+% be set with \cs{fp_set_variable:nn} to arbitrary floating point
+% expressions including other variables.
+%
+% \begin{function}[added = 2023-10-19]{\fp_new_variable:n}
+% \begin{syntax}
+% \cs{fp_new_variable:n} \Arg{identifier}
+% \end{syntax}
+% Declares the \meta{identifier} as a variable, which allows it to be
+% used in floating point expressions. For instance,
+% \begin{quote}
+% \cs{fp_new_variable:n} |{ A }| \\
+% \cs{fp_show:n} |{ A**2 - A + 1 }|
+% \end{quote}
+% shows |(((A^2)-A)+1)|. If the declaration was missing, the parser
+% would complain about an \enquote{\texttt{Unknown fp word 'A'}}. The
+% \meta{identifier} must consist entirely of Latin letters among
+% |[a-zA-Z]|.
+% \end{function}
+%
+% \begin{function}[added = 2023-10-19]{\fp_set_variable:nn}
+% \begin{syntax}
+% \cs{fp_set_variable:nn} \Arg{identifier} \Arg{fp expr}
+% \end{syntax}
+% Defines the \meta{identifier} to stand in any further expression for
+% the result of evaluating the \meta{floating point expression} as
+% much as possible. The result may contain other variables, which are
+% then replaced by their values if they have any. For instance,
+% \begin{quote}\let\obeyedline=\newline\obeylines^^A
+% \cs{fp_new_variable:n} |{ A }|
+% \cs{fp_new_variable:n} |{ B }|
+% \cs{fp_new_variable:n} |{ C }|
+% \cs{fp_set_variable:nn} |{ A } { 3 }|
+% \cs{fp_set_variable:nn} |{ C } { A ** 2 + B * 1 }|
+% \cs{fp_show:n} |{ C + 4 }|
+% \cs{fp_set_variable:nn} |{ A } { 4 }|
+% \cs{fp_show:n} |{ C + 4 }|
+% \end{quote}
+% shows |((9+(B*1))+4)| twice: changing the value of~|A| to~|4| does
+% not alter~|C| because |A|~was replaced by its value~|3| when
+% evaluating |A**2+B*1|.
+% \end{function}
+%
+% \begin{function}[added = 2023-10-19]{\fp_clear_variable:n}
+% \begin{syntax}
+% \cs{fp_clear_variable:n} \Arg{identifier}
+% \end{syntax}
+% Removes any value given by \cs{fp_set_variable:nn} to the variable
+% with this \meta{identifier}. For instance,
+% \begin{quote}\let\obeyedline=\newline\obeylines^^A
+% \cs{fp_new_variable:n} |{ A }|
+% \cs{fp_set_variable:nn} |{ A } { 3 }|
+% \cs{fp_show:n} |{ A ^ 2 }|
+% \cs{fp_clear_variable:n} |{ A }|
+% \cs{fp_show:n} |{ A ^ 2 }|
+% \end{quote}
+% shows~|9|, then~|(A^2)|.
+% \end{function}
+%
+% \section{User-defined functions}
+%
+% It is possible to define new user functions which can be used inside
+% the argument to \cs{fp_eval:n}, etc. These functions may take one or
+% more named arguments, and should be implemented using expansion methods
+% only.
+%
+% \begin{function}[added = 2023-10-19]{\fp_new_function:n}
+% \begin{syntax}
+% \cs{fp_new_function:n} \Arg{identifier}
+% \end{syntax}
+% Declares the \meta{identifier} as a function, which allows it to be
+% used in floating point expressions. For instance,
+% \begin{quote}
+% \cs{fp_new_function:n} |{ foo }| \\
+% \cs{fp_show:n} |{ foo ( 1 + 2 , foo(3), A ) ** 2 } }|
+% \end{quote}
+% shows |(foo(3, foo(3), A))^(2)|. If the declaration was missing,
+% the parser would complain about an \enquote{\texttt{Unknown fp word 'foo'}}.
+% The \meta{identifier} must consist entirely of Latin letters |[a-zA-Z]|.
+% \end{function}
+%
+% \begin{function}[added = 2023-10-19]{\fp_set_function:nnn}
+% \begin{syntax}
+% \cs{fp_set_function:nnn} \Arg{identifier} \Arg{vars} \Arg{fp expr}
+% \end{syntax}
+% Defines the \meta{identifier} to stand in any further expression for
+% the result of evaluating the \meta{floating point expression}, with
+% the \meta{identifier} accepting the \meta{vars} (a comma list).
+% The result may contain other functions, which are
+% then replaced by their results if they have any. For instance,
+% \begin{quote}
+% \cs{fp_new_function:n} |{ foo }| \\
+% \cs{fp_set_function:nnn} |{ npow } { a,b } { a**b }| \\
+% \cs{fp_show:n} |{ npow(16,0.25) } }|
+% \end{quote}
+% shows |2|. The names of the \meta{vars} must
+% consist entirely of Latin letters |[a-zA-Z]|, but are otherwise not
+% restricted: in particular, they are independent of any variables
+% declared by \cs{fp_new_variable:n}.
+% \end{function}
+%
+% \begin{function}[added = 2023-10-19]{\fp_clear_function:n}
+% \begin{syntax}
+% \cs{fp_clear_function:n} \Arg{identifier}
+% \end{syntax}
+% Removes any definition given by \cs{fp_set_function:nnn} to the function
+% with this \meta{identifier}.
+% \end{function}
+%
% \section{Some useful constants, and scratch variables}
%
% \begin{variable}[added = 2012-05-08, module = fp]{\c_zero_fp, \c_minus_zero_fp}
@@ -1417,7 +1549,7 @@
% \begin{function}[EXP, added = 2012-09-26, tested = m3fp-convert003]
% {\fp_max:nn, \fp_min:nn}
% \begin{syntax}
-% \cs{fp_max:nn} \Arg{fp expression 1} \Arg{fp expression 2}
+% \cs{fp_max:nn} \Arg{fp expr_1} \Arg{fp expr_2}
% \end{syntax}
% Evaluates the \meta{fp exprs} as described for
% \cs{fp_eval:n} and leaves the resulting larger (\texttt{max}) or
diff --git a/macros/latex/contrib/l3kernel/l3fparray.dtx b/macros/latex/contrib/l3kernel/l3fparray.dtx
index 9929135baa..36d84a593d 100644
--- a/macros/latex/contrib/l3kernel/l3fparray.dtx
+++ b/macros/latex/contrib/l3kernel/l3fparray.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3int.dtx b/macros/latex/contrib/l3kernel/l3int.dtx
index e012e191d2..c1dc697e71 100644
--- a/macros/latex/contrib/l3kernel/l3int.dtx
+++ b/macros/latex/contrib/l3kernel/l3int.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -94,7 +94,7 @@
% \int_show:n { \l_my_tl + \l_my_int * 3 - ( 3 + 4 * 5 ) }
% \end{verbatim}
% show the same result $-6$ because \cs[no-index]{l_my_tl} expands to
-% the integer denotation~|5| while the integer variable \cs{l_my_int}
+% the integer denotation~|5| while the integer variable \cs[no-index]{l_my_int}
% takes the value~$4$. As the \meta{integer expression} is fully
% expanded from left to right during evaluation, fully expandable and
% restricted-expandable functions can both be used, and \cs{exp_not:n}
diff --git a/macros/latex/contrib/l3kernel/l3intarray.dtx b/macros/latex/contrib/l3kernel/l3intarray.dtx
index 10458ad602..cbfdc48666 100644
--- a/macros/latex/contrib/l3kernel/l3intarray.dtx
+++ b/macros/latex/contrib/l3kernel/l3intarray.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3kernel-functions.dtx b/macros/latex/contrib/l3kernel/l3kernel-functions.dtx
index d517f72a22..ce3ab20970 100644
--- a/macros/latex/contrib/l3kernel/l3kernel-functions.dtx
+++ b/macros/latex/contrib/l3kernel/l3kernel-functions.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3keys.dtx b/macros/latex/contrib/l3kernel/l3keys.dtx
index 95ddcd0a38..9fea120c91 100644
--- a/macros/latex/contrib/l3kernel/l3keys.dtx
+++ b/macros/latex/contrib/l3kernel/l3keys.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -385,10 +385,10 @@
% \begin{syntax}
% \meta{key} .legacy_if_set:n = \meta{switch}
% \end{syntax}
-% Defines \meta{key} to set legacy \cs{if} \meta{switch} to \meta{value}
+% Defines \meta{key} to set legacy \cs[no-index]{if\meta{switch}} to \meta{value}
% (which must be either \enquote{\texttt{true}} or \enquote{\texttt{false}}).
% The \meta{switch} is the name of the switch \emph{without the leading
-% \cs{if}}.
+% \texttt{if}}.
%
% The \texttt{inverse} versions will set the \meta{switch} to the logical
% opposite of the \meta{value}.
@@ -740,16 +740,12 @@
% \end{function}
%
% \begin{variable}[updated = 2020-02-08]
-% {\l_keys_key_str, \l_keys_path_str, \l_keys_value_tl}
+% {\l_keys_path_str, \l_keys_key_str, \l_keys_value_tl}
% For each key processed, information of the full \emph{path} of the
% key, the \emph{name} of the key and the \emph{value} of the key is
% available within two string and one token list variables.
% These may be used within the code of the key.
%
-% The \emph{value} is everything after the \texttt{=}, which may be
-% empty if no value was given. This is stored in \cs{l_keys_value_tl}, and
-% is not processed in any way by \cs{keys_set:nn}.
-%
% The \emph{path} of the key is a \enquote{full} description of the key,
% and is unique for each key. It consists of the module and full key name,
% thus for example
@@ -767,6 +763,10 @@
% \texttt{/}, and thus is not unique. In the preceding examples, both keys
% have name \texttt{key-a} despite having different paths. This information
% is stored in \cs{l_keys_key_str}.
+%
+% The \emph{value} is everything after the \texttt{=}, which may be
+% empty if no value was given. This is stored in \cs{l_keys_value_tl}, and
+% is not processed in any way by \cs{keys_set:nn}.
% \end{variable}
%
% \section{Handling of unknown keys}
@@ -788,10 +788,10 @@
% {
% \keys_set_known:nn, \keys_set_known:nV,
% \keys_set_known:nv, \keys_set_known:ne,
-% \keys_set_known:no
+% \keys_set_known:no,
% \keys_set_known:nnN, \keys_set_known:nVN,
% \keys_set_known:nvN, \keys_set_known:neN,
-% \keys_set_known:noN
+% \keys_set_known:noN,
% \keys_set_known:nnnN, \keys_set_known:nVnN,
% \keys_set_known:nvnN, \keys_set_known:nenN,
% \keys_set_known:nonN
diff --git a/macros/latex/contrib/l3kernel/l3legacy.dtx b/macros/latex/contrib/l3kernel/l3legacy.dtx
index 92b8cdb971..78adefa2da 100644
--- a/macros/latex/contrib/l3kernel/l3legacy.dtx
+++ b/macros/latex/contrib/l3kernel/l3legacy.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -60,7 +60,7 @@
% \cs{legacy_if:nTF} \Arg{name} \Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the \LaTeXe{}/plain \TeX{} conditional (generated by \tn{newif})
-% if \texttt{true} or \texttt{false} and branches accordingly. The
+% is \texttt{true} or \texttt{false} and branches accordingly. The
% \meta{name} of the conditional should \emph{omit} the leading \texttt{if}.
% \end{function}
%
diff --git a/macros/latex/contrib/l3kernel/l3luatex.dtx b/macros/latex/contrib/l3kernel/l3luatex.dtx
index c7832c892d..c0ec4f69a0 100644
--- a/macros/latex/contrib/l3kernel/l3luatex.dtx
+++ b/macros/latex/contrib/l3kernel/l3luatex.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3msg.dtx b/macros/latex/contrib/l3kernel/l3msg.dtx
index 4feb4115a1..382aab68dd 100644
--- a/macros/latex/contrib/l3kernel/l3msg.dtx
+++ b/macros/latex/contrib/l3kernel/l3msg.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3names.dtx b/macros/latex/contrib/l3kernel/l3names.dtx
index f299b21579..e85262831f 100644
--- a/macros/latex/contrib/l3kernel/l3names.dtx
+++ b/macros/latex/contrib/l3kernel/l3names.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3news.pdf b/macros/latex/contrib/l3kernel/l3news.pdf
index 7f0effadb8..b5c1844444 100644
--- a/macros/latex/contrib/l3kernel/l3news.pdf
+++ b/macros/latex/contrib/l3kernel/l3news.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news01.pdf b/macros/latex/contrib/l3kernel/l3news01.pdf
index 5508abfcc9..4d0a8ae25d 100644
--- a/macros/latex/contrib/l3kernel/l3news01.pdf
+++ b/macros/latex/contrib/l3kernel/l3news01.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news02.pdf b/macros/latex/contrib/l3kernel/l3news02.pdf
index 13e40ab8bd..7342946a43 100644
--- a/macros/latex/contrib/l3kernel/l3news02.pdf
+++ b/macros/latex/contrib/l3kernel/l3news02.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news03.pdf b/macros/latex/contrib/l3kernel/l3news03.pdf
index f80fc2a519..331b9cf1b4 100644
--- a/macros/latex/contrib/l3kernel/l3news03.pdf
+++ b/macros/latex/contrib/l3kernel/l3news03.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news04.pdf b/macros/latex/contrib/l3kernel/l3news04.pdf
index c33cbf0cac..b860cf5ff4 100644
--- a/macros/latex/contrib/l3kernel/l3news04.pdf
+++ b/macros/latex/contrib/l3kernel/l3news04.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news05.pdf b/macros/latex/contrib/l3kernel/l3news05.pdf
index ffe3a03c6c..7e616f5a29 100644
--- a/macros/latex/contrib/l3kernel/l3news05.pdf
+++ b/macros/latex/contrib/l3kernel/l3news05.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news06.pdf b/macros/latex/contrib/l3kernel/l3news06.pdf
index e25a8421bb..77334146c0 100644
--- a/macros/latex/contrib/l3kernel/l3news06.pdf
+++ b/macros/latex/contrib/l3kernel/l3news06.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news07.pdf b/macros/latex/contrib/l3kernel/l3news07.pdf
index 4159983011..1193adac7e 100644
--- a/macros/latex/contrib/l3kernel/l3news07.pdf
+++ b/macros/latex/contrib/l3kernel/l3news07.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news08.pdf b/macros/latex/contrib/l3kernel/l3news08.pdf
index 8d74fc5968..ae70965ba3 100644
--- a/macros/latex/contrib/l3kernel/l3news08.pdf
+++ b/macros/latex/contrib/l3kernel/l3news08.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news09.pdf b/macros/latex/contrib/l3kernel/l3news09.pdf
index d4c60d81f7..d9791e7186 100644
--- a/macros/latex/contrib/l3kernel/l3news09.pdf
+++ b/macros/latex/contrib/l3kernel/l3news09.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news10.pdf b/macros/latex/contrib/l3kernel/l3news10.pdf
index 7b5dcec9cc..366041530a 100644
--- a/macros/latex/contrib/l3kernel/l3news10.pdf
+++ b/macros/latex/contrib/l3kernel/l3news10.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news11.pdf b/macros/latex/contrib/l3kernel/l3news11.pdf
index 1cfeef5b06..410448f654 100644
--- a/macros/latex/contrib/l3kernel/l3news11.pdf
+++ b/macros/latex/contrib/l3kernel/l3news11.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3news12.pdf b/macros/latex/contrib/l3kernel/l3news12.pdf
index cd159d28f3..127946bd80 100644
--- a/macros/latex/contrib/l3kernel/l3news12.pdf
+++ b/macros/latex/contrib/l3kernel/l3news12.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3pdf.dtx b/macros/latex/contrib/l3kernel/l3pdf.dtx
index f583b393ca..9c6172caaf 100644
--- a/macros/latex/contrib/l3kernel/l3pdf.dtx
+++ b/macros/latex/contrib/l3kernel/l3pdf.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3prefixes.csv b/macros/latex/contrib/l3kernel/l3prefixes.csv
index 710da8edbe..8b4ead7bf3 100644
--- a/macros/latex/contrib/l3kernel/l3prefixes.csv
+++ b/macros/latex/contrib/l3kernel/l3prefixes.csv
@@ -22,6 +22,7 @@ backslash,l3kernel,The LaTeX Project,https://www.latex-project.org/latex3.html,h
bearwear,bearwear,Ulrike Fischer,https://github.com/u-fischer/bearwear,https://github.com/u-fischer/bearwear,https://github.com/u-fischer/bearwear/issues,2020-04-24,2020-04-24,
beuron,beuron,Keno Wehr,https://ctan.org/pkg/beuron,,,2021-08-23,2021-08-23,
bitset,l3kernel,The LaTeX3 Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex3.git,https://github.com/latex3/latex3/issues,2020-12-26,2020-12-26,
+block,latex2e,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex2e.git,https://github.com/latex3/latex2e/issues,2023-10-17,2023-10-17,
bool,l3kernel,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex3.git,https://github.com/latex3/latex3/issues,2012-09-27,2012-09-27,
box,l3kernel,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex3.git,https://github.com/latex3/latex3/issues,2012-09-27,2012-09-27,
bxjh,BXjaholiday,Takuto Asakura,https://github.com/wtsnjp/BXjaholiday,https://github.com/wtsnjp/BXjaholiday.git,https://github.com/wtsnjp/BXjaholiday/issues,2018-02-02,2019-02-02,
@@ -92,6 +93,7 @@ fltr,newlfm,Paul Thomson,,,,2013-01-29,2013-01-29,
fmdug,dashundergaps,Frank Mittelbach,https://www.latex-project.org/,https://github.com/FrankMittelbach/fmitex-dashundergaps.git,https://github.com/FrankMittelbach/fmitex-dashundergaps/issues,2018-06-24,2021-10-11,
fmuft,unicodefonttable,Frank Mittelbach,https://www.latex-project.org/,https://github.com/FrankMittelbach/fmitex-unicodefonttable.git,https://github.com/FrankMittelbach/fmitex-unicodefonttable/issues,2020-02-17,2021-10-11,
fmwao,widows-and-orphans,Frank Mittelbach,https://www.latex-project.org/,https://github.com/FrankMittelbach/fmitex-widows-and-orphans.git,https://github.com/FrankMittelbach/fmitex-widows-and-orphans/issues,2018-09-26,2018-09-26,
+fnote,latex2e,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex2e.git,https://github.com/latex3/latex2e/issues,2023-10-17,2023-10-17,
fnpct,fnpct,Clemens Niederberger,https://github.com/cgnieder/fnpct/,https://github.com/cgnieder/fnpct.git,https://github.com/cgnieder/fnpct/issues,2013-03-16,2020-04-14,
fontsizes,fontsizes,Julien Rivaud,,,,,2018-06-13,
fontspec,fontspec,Will Robertson,https://github.com/wspr/fontspec,https://github.com/wspr/fontspec.git,https://github.com/wspr/fontspec/issues,2013-03-16,2013-03-16,
@@ -227,6 +229,8 @@ silly,sillypage,Paulo Cereda,https://github.com/cereda/sillypage,https://github.
siunitx,siunitx,Joseph Wright,https://github.com/josephwright/siunitx,https://github.com/josephwright/siunitx.git,https://github.com/josephwright/siunitx/issues,2012-11-04,2012-11-04,
skel,skeldoc,Magnus Lie Hetland,https://github.com/mlhetland/skeldoc.sty,https://github.com/mlhetland/skeldoc.sty.git,https://github.com/mlhetland/skeldoc.sty/issues,2021-01-04,2021-01-04,
skip,l3kernel,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex3.git,https://github.com/latex3/latex3/issues,2012-09-27,2012-09-27,
+slcd,se2thesis,Stephan Lukasczyk,https://github.com/se2p/se2thesis,https://github.com/se2p/se2thesis,https://github.com/se2p/se2thesis/issues,2023-10-18,2023-10-18,
+socket,latex2e,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex2e.git,https://github.com/latex3/latex2e/issues,2023-10-17,2023-10-17,
sort,l3kernel,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex3.git,https://github.com/latex3/latex3/issues,2012-09-27,2017-02-13,
space,l3kernel,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex3.git,https://github.com/latex3/latex3/issues,2018-05-12,2018-05-12,
starray,starray,Alceu Frigeri,https://github.com/alceu-frigeri/starray,https://github.com/alceu-frigeri/starray,https://github.com/alceu-frigeri/starray/issues,2023-05-15,2023-05-15,
diff --git a/macros/latex/contrib/l3kernel/l3prefixes.pdf b/macros/latex/contrib/l3kernel/l3prefixes.pdf
index 5d41b138f0..de3f86bdb7 100644
--- a/macros/latex/contrib/l3kernel/l3prefixes.pdf
+++ b/macros/latex/contrib/l3kernel/l3prefixes.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3prg.dtx b/macros/latex/contrib/l3kernel/l3prg.dtx
index e3f09d90d3..c676e7343e 100644
--- a/macros/latex/contrib/l3kernel/l3prg.dtx
+++ b/macros/latex/contrib/l3kernel/l3prg.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -581,7 +581,7 @@
% \begin{syntax}
% \cs{bool_until_do:Nn} \meta{boolean} \Arg{code}
% \end{syntax}
-% This function firsts checks the logical value of the \meta{boolean}.
+% This function first checks the logical value of the \meta{boolean}.
% If it is \texttt{false} the \meta{code} is placed in the input stream
% and expanded. After the completion of the \meta{code} the truth
% of the \meta{boolean} is re-evaluated. The process then loops
@@ -592,7 +592,7 @@
% \begin{syntax}
% \cs{bool_while_do:Nn} \meta{boolean} \Arg{code}
% \end{syntax}
-% This function firsts checks the logical value of the \meta{boolean}.
+% This function first checks the logical value of the \meta{boolean}.
% If it is \texttt{true} the \meta{code} is placed in the input stream
% and expanded. After the completion of the \meta{code} the truth
% of the \meta{boolean} is re-evaluated. The process then loops
@@ -627,7 +627,7 @@
% \begin{syntax}
% \cs{bool_until_do:nn} \Arg{boolean expression} \Arg{code}
% \end{syntax}
-% This function firsts checks the logical value of the
+% This function first checks the logical value of the
% \meta{boolean expression} (as described for \cs{bool_if:nTF}).
% If it is \texttt{false} the \meta{code} is placed in the input stream
% and expanded. After the completion of the \meta{code} the truth
@@ -639,7 +639,7 @@
% \begin{syntax}
% \cs{bool_while_do:nn} \Arg{boolean expression} \Arg{code}
% \end{syntax}
-% This function firsts checks the logical value of the
+% This function first checks the logical value of the
% \meta{boolean expression} (as described for \cs{bool_if:nTF}).
% If it is \texttt{true} the \meta{code} is placed in the input stream
% and expanded. After the completion of the \meta{code} the truth
@@ -808,7 +808,8 @@
% \cs{prg_break:n} \Arg{code} \ldots{} \cs{prg_break_point:}
% \end{syntax}
% Breaks a recursion which has no \meta{ending code} and which is not
-% a user-breakable mapping (see for instance \cs{prop_get:Nn}), and
+% a user-breakable mapping (see for instance
+% implementation of \cs{int_step_function:nnnN}), and
% inserts the \meta{code} in the input stream.
% \end{function}
%
diff --git a/macros/latex/contrib/l3kernel/l3prop.dtx b/macros/latex/contrib/l3kernel/l3prop.dtx
index 69cafe1cff..8fb7648af5 100644
--- a/macros/latex/contrib/l3kernel/l3prop.dtx
+++ b/macros/latex/contrib/l3kernel/l3prop.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -60,7 +60,7 @@
% Each entry in a property list must have a unique \meta{key}: if an entry is
% added to a property list which already contains the \meta{key} then the new
% entry overwrites the existing one. The \meta{keys} are compared on a
-% string basis, using the same method as \cs{str_if_eq:nn}.
+% string basis, using the same method as \cs{str_if_eq:nnTF}.
%
% Property lists are intended for storing key-based information for use within
% code. This is in contrast to key--value lists, which are a form of
diff --git a/macros/latex/contrib/l3kernel/l3quark.dtx b/macros/latex/contrib/l3kernel/l3quark.dtx
index 1a1e1aaf1f..d515229582 100644
--- a/macros/latex/contrib/l3kernel/l3quark.dtx
+++ b/macros/latex/contrib/l3kernel/l3quark.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3regex.dtx b/macros/latex/contrib/l3kernel/l3regex.dtx
index 87dfcec47b..cd7bd9f33b 100644
--- a/macros/latex/contrib/l3kernel/l3regex.dtx
+++ b/macros/latex/contrib/l3kernel/l3regex.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -921,7 +921,7 @@
% \item Optimize states with a single \cs[no-index]{__regex_action_free:n}.
% \item Optimize the use of \cs[no-index]{__regex_action_success:} by inserting it
% in state $2$ directly instead of having an extra transition.
-% \item Optimize the use of \cs{int_step_...} functions.
+% \item Optimize the use of \cs[no-index]{int_step_...} functions.
% \item Groups don't capture within regexes for csnames; optimize and
% document.
% \item Better \enquote{show} for anchors, properties, and catcode tests.
@@ -930,7 +930,7 @@
% numbers.
% \item Instead of checking whether the character is special or
% alphanumeric using its character code, check if it is special in
-% regexes with \cs{cs_if_exist} tests.
+% regexes with \cs[no-index]{cs_if_exist} tests.
% \end{itemize}
%
% The following features are likely to be implemented at some point
diff --git a/macros/latex/contrib/l3kernel/l3seq.dtx b/macros/latex/contrib/l3kernel/l3seq.dtx
index 9572261d46..56662dc623 100644
--- a/macros/latex/contrib/l3kernel/l3seq.dtx
+++ b/macros/latex/contrib/l3kernel/l3seq.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3skip.dtx b/macros/latex/contrib/l3kernel/l3skip.dtx
index 0371b7ecad..3130ef8597 100644
--- a/macros/latex/contrib/l3kernel/l3skip.dtx
+++ b/macros/latex/contrib/l3kernel/l3skip.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3sort.dtx b/macros/latex/contrib/l3kernel/l3sort.dtx
index 6837e7fb0e..0a987712f3 100644
--- a/macros/latex/contrib/l3kernel/l3sort.dtx
+++ b/macros/latex/contrib/l3kernel/l3sort.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3str-convert.dtx b/macros/latex/contrib/l3kernel/l3str-convert.dtx
index f4bfaf2c2c..c4fc416d42 100644
--- a/macros/latex/contrib/l3kernel/l3str-convert.dtx
+++ b/macros/latex/contrib/l3kernel/l3str-convert.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3str.dtx b/macros/latex/contrib/l3kernel/l3str.dtx
index 300a779bd1..99c0f980a5 100644
--- a/macros/latex/contrib/l3kernel/l3str.dtx
+++ b/macros/latex/contrib/l3kernel/l3str.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -752,7 +752,7 @@
% \item Case changing text for typesetting: see the
% \cs[index=text_lowercase:n]{text_lowercase:n(n)},
% \cs[index=text_uppercase:n]{text_uppercase:n(n)} and
-% \cs[index=text_titlecase:n]{text_titlecase:n(n)} functions which
+% \cs[index=text_titlecase_all:n]{text_titlecase_(all|once):n(n)} functions which
% correctly deal with context-dependence and other factors appropriate
% to text case changing.
% \end{itemize}
@@ -1138,7 +1138,7 @@
% \end{macro}
%
% \begin{macro}[EXP]{\@@_if_eq:nn}
-% String comparisons rely on the primitive \cs[index=pdfstrcmp]{(pdf)strcmp},
+% String comparisons rely on the primitive \tn[index=pdfstrcmp]{(pdf)strcmp},
% so we define a new name for it.
% \begin{macrocode}
\cs_new_eq:NN \@@_if_eq:nn \tex_strcmp:D
diff --git a/macros/latex/contrib/l3kernel/l3styleguide.pdf b/macros/latex/contrib/l3kernel/l3styleguide.pdf
index 16d307e028..945554d2f4 100644
--- a/macros/latex/contrib/l3kernel/l3styleguide.pdf
+++ b/macros/latex/contrib/l3kernel/l3styleguide.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3styleguide.tex b/macros/latex/contrib/l3kernel/l3styleguide.tex
index 29c2f76864..995a5d3668 100644
--- a/macros/latex/contrib/l3kernel/l3styleguide.tex
+++ b/macros/latex/contrib/l3kernel/l3styleguide.tex
@@ -32,7 +32,7 @@ The released version of this bundle is available from CTAN.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2023-10-10}
+\date{Released 2023-10-23}
\begin{document}
diff --git a/macros/latex/contrib/l3kernel/l3syntax-changes.pdf b/macros/latex/contrib/l3kernel/l3syntax-changes.pdf
index 5c4fe8ad1d..f2db75a12a 100644
--- a/macros/latex/contrib/l3kernel/l3syntax-changes.pdf
+++ b/macros/latex/contrib/l3kernel/l3syntax-changes.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3syntax-changes.tex b/macros/latex/contrib/l3kernel/l3syntax-changes.tex
index dbb6d858b4..d93e7bc8dc 100644
--- a/macros/latex/contrib/l3kernel/l3syntax-changes.tex
+++ b/macros/latex/contrib/l3kernel/l3syntax-changes.tex
@@ -32,7 +32,7 @@ The released version of this bundle is available from CTAN.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2023-10-10}
+\date{Released 2023-10-23}
\newcommand{\TF}{\textit{(TF)}}
diff --git a/macros/latex/contrib/l3kernel/l3sys.dtx b/macros/latex/contrib/l3kernel/l3sys.dtx
index 5e57590767..577e4daa19 100644
--- a/macros/latex/contrib/l3kernel/l3sys.dtx
+++ b/macros/latex/contrib/l3kernel/l3sys.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -299,7 +299,7 @@
% enabled. This returns false if unrestricted shell escape is
% enabled. Unrestricted shell escape is not considered a superset
% of restricted shell escape in this case. To find whether any
-% shell escape is enabled use \cs{sys_if_shell:}.
+% shell escape is enabled use \cs{sys_if_shell:TF}.
% \end{function}
%
% \begin{function}[added = 2017-05-27]
diff --git a/macros/latex/contrib/l3kernel/l3term-glossary.pdf b/macros/latex/contrib/l3kernel/l3term-glossary.pdf
index ebe1f75c91..ffdbc76f29 100644
--- a/macros/latex/contrib/l3kernel/l3term-glossary.pdf
+++ b/macros/latex/contrib/l3kernel/l3term-glossary.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/l3term-glossary.tex b/macros/latex/contrib/l3kernel/l3term-glossary.tex
index bd166834ac..25a510d9e6 100644
--- a/macros/latex/contrib/l3kernel/l3term-glossary.tex
+++ b/macros/latex/contrib/l3kernel/l3term-glossary.tex
@@ -32,7 +32,7 @@ The released version of this bundle is available from CTAN.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2023-10-10}
+\date{Released 2023-10-23}
\newcommand{\TF}{\textit{(TF)}}
diff --git a/macros/latex/contrib/l3kernel/l3text-case.dtx b/macros/latex/contrib/l3kernel/l3text-case.dtx
index 0e20a797f0..e34e9043a5 100644
--- a/macros/latex/contrib/l3kernel/l3text-case.dtx
+++ b/macros/latex/contrib/l3kernel/l3text-case.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -77,16 +77,17 @@
% {
% \text_lowercase:n,
% \text_uppercase:n,
-% \text_titlecase:n,
+% \text_titlecase_all:n,
% \text_titlecase_first:n
% }
% \begin{macro}[EXP]
% {
% \text_lowercase:nn,
% \text_uppercase:nn,
-% \text_titlecase:nn,
+% \text_titlecase_all:nn,
% \text_titlecase_first:nn
% }
+% \begin{macro}[EXP]{\@@_change_case:nnn}
% The user level functions here are all wrappers around the internal
% functions for case changing.
% \begin{macrocode}
@@ -94,31 +95,34 @@
{ \@@_change_case:nnn { lower } { } {#1} }
\cs_new:Npn \text_uppercase:n #1
{ \@@_change_case:nnn { upper } { } {#1} }
-\cs_new:Npn \text_titlecase:n #1
+\cs_new:Npn \text_titlecase_all:n #1
{ \@@_change_case:nnn { title } { } {#1} }
\cs_new:Npn \text_titlecase_first:n #1
- { \@@_change_case:nnn { titleonly } { } {#1} }
+ { \@@_change_case:nnnn { title } { break } { } {#1} }
\cs_new:Npn \text_lowercase:nn #1#2
{ \@@_change_case:nnn { lower } {#1} {#2} }
\cs_new:Npn \text_uppercase:nn #1#2
{ \@@_change_case:nnn { upper } {#1} {#2} }
-\cs_new:Npn \text_titlecase:nn #1#2
+\cs_new:Npn \text_titlecase_all:nn #1#2
{ \@@_change_case:nnn { title } {#1} {#2} }
\cs_new:Npn \text_titlecase_first:nn #1#2
- { \@@_change_case:nnn { titleonly } {#1} {#2} }
+ { \@@_change_case:nnnn { title } { break } {#1} {#2} }
+\cs_new:Npn \@@_change_case:nnn #1#2#3
+ { \@@_change_case:nnnn {#1} {#1} {#2} {#3} }
% \end{macrocode}
% \end{macro}
% \end{macro}
+% \end{macro}
%
% \begin{macro}[EXP]
% {
-% \@@_change_case:nnn ,
-% \@@_change_case_auxi:nnn ,
-% \@@_change_case_auxii:nnn
+% \@@_change_case:nnnn ,
+% \@@_change_case_auxi:nnnn ,
+% \@@_change_case_auxii:nnnn
% }
-% \begin{macro}[EXP]{\@@_change_case_BCP:nnn}
-% \begin{macro}[EXP]{\@@_change_case_BCP:nnw}
-% \begin{macro}[EXP]{\@@_change_case_BCP:nnnnw}
+% \begin{macro}[EXP]{\@@_change_case_BCP:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_BCP:nnnw}
+% \begin{macro}[EXP]{\@@_change_case_BCP:nnnnnw}
% \begin{macro}[EXP]
% {
% \@@_change_case_store:n, \@@_change_case_store:o,
@@ -128,74 +132,69 @@
% \begin{macro}[EXP]{\@@_change_case_store:nw}
% \begin{macro}[EXP]{\@@_change_case_result:n}
% \begin{macro}[EXP]{\@@_change_case_end:w}
-% \begin{macro}[EXP]{\@@_change_case_loop:nnw}
-% \begin{macro}[EXP]{\@@_change_case_break:w}
+% \begin{macro}[EXP]{\@@_change_case_loop:nnnw}
+% \begin{macro}[EXP]{\@@_change_case_break:w, \@@_change_case_break_aux:w}
% \begin{macro}[EXP]
% {
-% \@@_change_case_group_lower:nnn ,
-% \@@_change_case_group_upper:nnn ,
-% \@@_change_case_group_title:nnn ,
-% \@@_change_case_group_titleonly:nnn
+% \@@_change_case_group_lower:nnnn ,
+% \@@_change_case_group_upper:nnnn ,
+% \@@_change_case_group_title:nnnn
% }
-% \begin{macro}[EXP]{\@@_change_case_space:nnw}
% \begin{macro}[EXP]
-% {\@@_change_case_N_type:nnN, \@@_change_case_N_type_aux:nnN}
-% \begin{macro}[EXP]{\@@_change_case_N_type:nnnN}
-% \begin{macro}[EXP]{\@@_change_case_math_search:nnNNN}
-% \begin{macro}[EXP]{\@@_change_case_math_loop:nnNw}
-% \begin{macro}[EXP]{\@@_change_case_math_N_type:nnNN}
-% \begin{macro}[EXP]{\@@_change_case_math_group:nnNn}
-% \begin{macro}[EXP]{\@@_change_case_math_space:nnNw}
-% \begin{macro}[EXP]{\@@_change_case_cs_check:nnN}
-% \begin{macro}[EXP]{\@@_change_case_exclude:nnN}
-% \begin{macro}[EXP]{\@@_change_case_exclude:nnnN}
-% \begin{macro}[EXP]{\@@_change_case_exclude:nnNN}
-% \begin{macro}[EXP]{\@@_change_case_exclude:nnNw}
-% \begin{macro}[EXP]{\@@_change_case_exclude:nnNnn}
-% \begin{macro}[EXP]{\@@_change_case_replace:nnN}
-% \begin{macro}[EXP]{\@@_change_case_replace:nnn, \@@_change_case_replace:vnn}
-% \begin{macro}[EXP]{\@@_change_case_switch:nnN}
+% {\@@_change_case_space:nnnw, \@@_change_case_space_break:nnnw}
% \begin{macro}[EXP]
-% {
-% \@@_change_case_switch_lower:nnNnnnn ,
-% \@@_change_case_switch_upper:nnNnnnn ,
-% \@@_change_case_switch_title:nnNnnnn ,
-% \@@_change_case_switch_titleonly:nnNnnnn
-% }
+% {\@@_change_case_N_type:nnnN, \@@_change_case_N_type_aux:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_N_type:nnnnN}
+% \begin{macro}[EXP]{\@@_change_case_math_search:nnnNNN}
+% \begin{macro}[EXP]{\@@_change_case_math_loop:nnnNw}
+% \begin{macro}[EXP]{\@@_change_case_math_N_type:nnnNN}
+% \begin{macro}[EXP]{\@@_change_case_math_group:nnnNn}
+% \begin{macro}[EXP]{\@@_change_case_math_space:nnnNw}
+% \begin{macro}[EXP]{\@@_change_case_cs_check:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_exclude:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_exclude:nnnnN}
+% \begin{macro}[EXP]{\@@_change_case_exclude:nnnNN}
+% \begin{macro}[EXP]{\@@_change_case_exclude:nnnNw}
+% \begin{macro}[EXP]{\@@_change_case_exclude:nnnNnn}
+% \begin{macro}[EXP]{\@@_change_case_replace:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_replace:nnnn, \@@_change_case_replace:vnnn}
+% \begin{macro}[EXP]{\@@_change_case_switch:nnnN}
% \begin{macro}[EXP]
% {
-% \@@_change_case_letterlike_lower:nnN ,
-% \@@_change_case_letterlike_upper:nnN ,
-% \@@_change_case_letterlike_title:nnN ,
-% \@@_change_case_letterlike_titleonly:nnN
+% \@@_change_case_switch_lower:nnnNnnnn ,
+% \@@_change_case_switch_upper:nnnNnnnn ,
+% \@@_change_case_switch_title:nnnNnnnn
% }
-% \begin{macro}[EXP]{\@@_change_case_letterlike:nnnnN}
+% \begin{macro}[EXP]{\@@_change_case_skip:nnw}
+% \begin{macro}[EXP]{\@@_change_case_skip_N_type:nnN}
+% \begin{macro}[EXP]{\@@_change_case_skip_group:nnn}
+% \begin{macro}[EXP]{\@@_change_case_skip_space:nnw}
% \begin{macro}[EXP]
% {
-% \@@_change_case_custom_lower:nnn ,
-% \@@_change_case_custom_title:nnn ,
-% \@@_change_case_custom_upper:nnn ,
-% \@@_change_case_custom_titleonly:nnn
+% \@@_change_case_letterlike_lower:nnnN ,
+% \@@_change_case_letterlike_upper:nnnN ,
+% \@@_change_case_letterlike_title:nnnN
% }
-% \begin{macro}[EXP]{\@@_change_case_custom:nnn}
+% \begin{macro}[EXP]{\@@_change_case_letterlike:nnnnnN}
% \begin{macro}[EXP]
% {
-% \@@_change_case_codepoint_lower:nnn ,
-% \@@_change_case_codepoint_upper:nnn ,
-% \@@_change_case_codepoint_title:nnn ,
-% \@@_change_case_codepoint_titleonly:nnn
+% \@@_change_case_custom_lower:nnnn ,
+% \@@_change_case_custom_title:nnnn ,
+% \@@_change_case_custom_upper:nnnn
% }
-% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnn}
-% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnw}
-% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_custom:nnnnn}
% \begin{macro}[EXP]
% {
-% \@@_change_case_codepoint_title:nn ,
-% \@@_change_case_codepoint_titleonly:nn
+% \@@_change_case_codepoint_lower:nnnn ,
+% \@@_change_case_codepoint_upper:nnnn ,
+% \@@_change_case_codepoint_title:nnnn
% }
-% \begin{macro}[EXP]{\@@_change_case_codepoint_title:nnnn}
-% \begin{macro}[EXP]
-% {\@@_change_case_codepoint:nnnn, \@@_change_case_codepoint_aux:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnnn}
+% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnnw}
+% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnnN}
+% \begin{macro}[EXP]{\@@_change_case_codepoint_title:nnn}
+% \begin{macro}[EXP]{\@@_change_case_codepoint_title:nnnnn}
+% \begin{macro}[EXP]{\@@_change_case_codepoint:nnnnn}
% \begin{macro}[EXP]{\@@_change_case_codepoint:nn}
% \begin{macro}[EXP]
% {
@@ -203,13 +202,15 @@
% \@@_change_case_codepoint:fnn ,
% \@@_change_case_codepoint_aux:nnn
% }
+% \begin{macro}[EXP]{\@@_change_case_codepoint_aux:nnn}
+% \begin{macro}[EXP]{\@@_change_case_codepoint_aux:nn}
+% \begin{macro}[EXP]{\@@_change_case_catcode:nn}
% \begin{macro}[EXP]
% {
-% \@@_change_case_next_lower:nn ,
-% \@@_change_case_next_upper:nn ,
-% \@@_change_case_next_title:nn ,
-% \@@_change_case_next_titleonly:nn ,
-% \@@_change_case_next_end:nn
+% \@@_change_case_next_lower:nnn ,
+% \@@_change_case_next_upper:nnn ,
+% \@@_change_case_next_title:nnn ,
+% \@@_change_case_next_end:nnn
% }
% As for the expansion code, the business end of case changing is the
% handling of \texttt{N}-type tokens. First, we expand the input fully
@@ -231,45 +232,50 @@
% wrap the entire result in exactly one \cs{exp_not:n}, or rather in the
% kernel version.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case:nnn #1#2#3
+\cs_new:Npn \@@_change_case:nnnn #1#2#3#4
{
\__kernel_exp_not:w \exp_after:wN
{
\exp:w
- \exp_args:Ne \@@_change_case_auxi:nnn
- { \text_expand:n {#3} }
- {#1} {#2}
+ \exp_args:Ne \@@_change_case_auxi:nnnn
+ { \text_expand:n {#4} }
+ {#1} {#2} {#3}
}
}
-\cs_new:Npn \@@_change_case_auxi:nnn #1#2#3
- { \exp_args:No \@@_change_case_BCP:nnn { \tl_to_str:n {#3} } {#1} {#2} }
-\cs_new:Npe \@@_change_case_BCP:nnn #1#2#3
+\cs_new:Npn \@@_change_case_auxi:nnnn #1#2#3#4
{
- \exp_not:N \@@_change_case_BCP:nnw
- {#2} {#3} #1 \tl_to_str:n { -x- -x- } \exp_not:N \q_@@_stop
+ \exp_args:No \@@_change_case_BCP:nnnn
+ { \tl_to_str:n {#4} } {#1} {#2} {#3}
+ }
+\cs_new:Npe \@@_change_case_BCP:nnnn #1#2#3#4
+ {
+ \exp_not:N \@@_change_case_BCP:nnnw
+ {#2} {#3} {#4} #1 \tl_to_str:n { -x- -x- } \exp_not:N \q_@@_stop
}
\use:e
{
- \cs_new:Npn \exp_not:N \@@_change_case_BCP:nnw
- #1#2#3 \tl_to_str:n { -x- } #4 \tl_to_str:n { -x- } #5
+ \cs_new:Npn \exp_not:N \@@_change_case_BCP:nnnw
+ #1#2#3#4 \tl_to_str:n { -x- } #5 \tl_to_str:n { -x- } #6
\exp_not:N \q_@@_stop
}
- { \@@_change_case_BCP:nnnnw {#1} {#2} {#4} {#3} #3 - - \q_@@_stop }
-\cs_new:Npn \@@_change_case_BCP:nnnnw #1#2#3#4#5 - #6 - #7 \q_@@_stop
+ { \@@_change_case_BCP:nnnnnw {#1} {#2} {#3} {#5} {#4} #4 - \q_@@_stop }
+\cs_new:Npn \@@_change_case_BCP:nnnnnw #1#2#3#4#5#6 - #7 \q_@@_stop
{
- \cs_if_exist:cTF { @@_change_case_ #2 _ #5 -x- #3 :nnnn }
- { \@@_change_case_auxii:nnn {#1} {#2} { #5 -x- #3 } }
+ \bool_lazy_or:nnTF
+ { \cs_if_exist_p:c { @@_change_case_ #2 _ #6 -x- #4 :nnnnn } }
+ { \tl_if_exist_p:c { l_@@_ #2 case_special_ #6 -x- #4 _tl } }
+ { \@@_change_case_auxii:nnnn {#1} {#2} {#3} { #6 -x- #4 } }
{
- \cs_if_exist:cTF { @@_change_case_ #2 _ #5 :nnnn }
- { \@@_change_case_auxii:nnn {#1} {#2} {#5} }
- { \@@_change_case_auxii:nnn {#1} {#2} {#4} }
+ \cs_if_exist:cTF { @@_change_case_ #2 _ #6 :nnnnn }
+ { \@@_change_case_auxii:nnnn {#1} {#2} {#3} {#6} }
+ { \@@_change_case_auxii:nnnn {#1} {#2} {#3} {#5} }
}
}
-\cs_new:Npn \@@_change_case_auxii:nnn #1#2#3
+\cs_new:Npn \@@_change_case_auxii:nnnn #1#2#3#4
{
\group_align_safe_begin:
- \cs_if_exist_use:c { @@_change_case_boundary_ #2 _ #3 :Nnnw }
- \@@_change_case_loop:nnw {#2} {#3} #1
+ \cs_if_exist_use:c { @@_change_case_boundary_ #2 _ #4 :Nnnnw }
+ \@@_change_case_loop:nnnw {#2} {#3} {#4} #1
\q_@@_recursion_tail \q_@@_recursion_stop
\@@_change_case_result:n { }
}
@@ -290,20 +296,23 @@
% \end{macrocode}
% The main loop is the standard \texttt{tl action} type.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_loop:nnw #1#2#3 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_loop:nnnw #1#2#3#4 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#3}
- { \@@_change_case_N_type:nnN }
+ \tl_if_head_is_N_type:nTF {#4}
+ { \@@_change_case_N_type:nnnN }
{
- \tl_if_head_is_group:nTF {#3}
- { \use:c { @@_change_case_group_ #1 :nnn } }
- { \@@_change_case_space:nnw }
+ \tl_if_head_is_group:nTF {#4}
+ { \use:c { @@_change_case_group_ #1 :nnnn } }
+ { \@@_change_case_space:nnnw }
}
- {#1} {#2} #3 \q_@@_recursion_stop
+ {#1} {#2} {#3} #4 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_break:w #1 \q_@@_recursion_tail \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_break:w
+ { \@@_change_case_break_aux:w \prg_do_nothing: }
+\cs_new:Npn \@@_change_case_break_aux:w
+ #1 \q_@@_recursion_tail \q_@@_recursion_stop
{
- \@@_change_case_store:n {#1}
+ \@@_change_case_store:o {#1}
\@@_change_case_end:w
}
% \end{macrocode}
@@ -315,53 +324,47 @@
% having too much testing, we use a two-step process here to allow the
% titlecase functions to be separate.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_group_lower:nnn #1#2#3
+\cs_new:Npn \@@_change_case_group_lower:nnnn #1#2#3#4
{
\@@_change_case_store:o
{
\exp_after:wN
{
\exp:w
- \@@_change_case_auxii:nnn {#3} {#1} {#2}
+ \@@_change_case_auxii:nnnn {#4} {#1} {#2} {#3}
}
}
- \@@_change_case_loop:nnw {#1} {#2}
+ \@@_change_case_loop:nnnw {#1} {#2} {#3}
}
-\cs_new_eq:NN \@@_change_case_group_upper:nnn
- \@@_change_case_group_lower:nnn
-\cs_new:Npn \@@_change_case_group_title:nnn #1#2#3
+\cs_new_eq:NN \@@_change_case_group_upper:nnnn
+ \@@_change_case_group_lower:nnnn
+\cs_new:Npn \@@_change_case_group_title:nnnn #1#2#3#4
{
\@@_change_case_store:o
{
\exp_after:wN
{
\exp:w
- \@@_change_case_auxii:nnn {#3} {#1} {#2}
+ \@@_change_case_auxii:nnnn {#4} {#1} {#2} {#3}
}
}
- \@@_change_case_loop:nnw { lower } {#2}
- }
-\cs_new:Npn \@@_change_case_group_titleonly:nnn #1#2#3
- {
- \@@_change_case_store:o
- {
- \exp_after:wN
- {
- \exp:w
- \@@_change_case_auxii:nnn {#3} {#1} {#2}
- }
- }
- \@@_change_case_break:w
+ \@@_change_case_skip:nnw {#2} {#3}
}
\use:e
{
- \cs_new:Npn \exp_not:N \@@_change_case_space:nnw #1#2 \c_space_tl
+ \cs_new:Npn \exp_not:N \@@_change_case_space:nnnw #1#2#3 \c_space_tl
}
{
\@@_change_case_store:n { ~ }
- \cs_if_exist_use:c { @@_change_case_boundary_ #1 _ #2 :Nnnw }
- \@@_change_case_loop:nnw {#1} {#2}
+ \cs_if_exist_use:cF { @@_change_case_space_ #2 :nnn }
+ {
+ \cs_if_exist_use:c { @@_change_case_boundary_ #1 _ #3 :Nnnnw }
+ \@@_change_case_loop:nnnw
+ }
+ {#2} {#2} {#3}
}
+\cs_new:Npn \@@_change_case_space_break:nnn #1#2#3
+ { \@@_change_case_break:w }
% \end{macrocode}
% The first step of handling \texttt{N}-type tokens is to filter out the
% end-of-loop. That has to be done separately from the first real step
@@ -371,85 +374,85 @@
% (i.e.~there is no assumption of \enquote{well-behaved} input in terms of
% math mode).
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_N_type:nnN #1#2#3
+\cs_new:Npn \@@_change_case_N_type:nnnN #1#2#3#4
{
- \@@_if_q_recursion_tail_stop_do:Nn #3
+ \@@_if_q_recursion_tail_stop_do:Nn #4
{ \@@_change_case_end:w }
- \@@_change_case_N_type_aux:nnN {#1} {#2} #3
+ \@@_change_case_N_type_aux:nnnN {#1} {#2} {#3} #4
}
-\cs_new:Npn \@@_change_case_N_type_aux:nnN #1#2#3
+\cs_new:Npn \@@_change_case_N_type_aux:nnnN #1#2#3#4
{
- \exp_args:NV \@@_change_case_N_type:nnnN
- \l_text_math_delims_tl {#1} {#2} #3
+ \exp_args:NV \@@_change_case_N_type:nnnnN
+ \l_text_math_delims_tl {#1} {#2} {#3} #4
}
-\cs_new:Npn \@@_change_case_N_type:nnnN #1#2#3#4
+\cs_new:Npn \@@_change_case_N_type:nnnnN #1#2#3#4#5
{
- \@@_change_case_math_search:nnNNN {#2} {#3} #4 #1
+ \@@_change_case_math_search:nnnNNN {#2} {#3} {#4} #5 #1
\q_@@_recursion_tail \q_@@_recursion_tail
\q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_math_search:nnNNN #1#2#3#4#5
+\cs_new:Npn \@@_change_case_math_search:nnnNNN #1#2#3#4#5#6
{
- \@@_if_q_recursion_tail_stop_do:Nn #4
- { \@@_change_case_cs_check:nnN {#1} {#2} #3 }
- \token_if_eq_meaning:NNTF #3 #4
+ \@@_if_q_recursion_tail_stop_do:Nn #5
+ { \@@_change_case_cs_check:nnnN {#1} {#2} {#3} #4 }
+ \token_if_eq_meaning:NNTF #4 #5
{
\@@_use_i_delimit_by_q_recursion_stop:nw
{
- \@@_change_case_store:n {#3}
- \@@_change_case_math_loop:nnNw {#1} {#2} #5
+ \@@_change_case_store:n {#4}
+ \@@_change_case_math_loop:nnnNw {#1} {#2} {#3} #6
}
}
- { \@@_change_case_math_search:nnNNN {#1} {#2} #3 }
+ { \@@_change_case_math_search:nnnNNN {#1} {#2} {#3} #4 }
}
-\cs_new:Npn \@@_change_case_math_loop:nnNw #1#2#3#4 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_math_loop:nnnNw #1#2#3#4#5 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_math_N_type:nnNN }
+ \tl_if_head_is_N_type:nTF {#5}
+ { \@@_change_case_math_N_type:nnnNN }
{
- \tl_if_head_is_group:nTF {#4}
- { \@@_change_case_math_group:nnNn }
- { \@@_change_case_math_space:nnNw }
+ \tl_if_head_is_group:nTF {#5}
+ { \@@_change_case_math_group:nnnNn }
+ { \@@_change_case_math_space:nnnNw }
}
- {#1} {#2} #3 #4 \q_@@_recursion_stop
+ {#1} {#2} {#3} #4 #5 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_math_N_type:nnNN #1#2#3#4
+\cs_new:Npn \@@_change_case_math_N_type:nnnNN #1#2#3#4#5
{
- \@@_if_q_recursion_tail_stop_do:Nn #4
+ \@@_if_q_recursion_tail_stop_do:Nn #5
{ \@@_change_case_end:w }
- \@@_change_case_store:n {#4}
- \token_if_eq_meaning:NNTF #4 #3
- { \@@_change_case_loop:nnw {#1} {#2} }
- { \@@_change_case_math_loop:nnNw {#1} {#2} #3 }
+ \@@_change_case_store:n {#5}
+ \token_if_eq_meaning:NNTF #5 #4
+ { \@@_change_case_loop:nnnw {#1} {#2} {#3} }
+ { \@@_change_case_math_loop:nnnNw {#1} {#2} {#3} #4 }
}
-\cs_new:Npn \@@_change_case_math_group:nnNn #1#2#3#4
+\cs_new:Npn \@@_change_case_math_group:nnnNn #1#2#3#4#5
{
- \@@_change_case_store:n { {#4} }
- \@@_change_case_math_loop:nnNw {#1} {#2} #3
+ \@@_change_case_store:n { {#5} }
+ \@@_change_case_math_loop:nnnNw {#1} {#2} {#3} #4
}
\use:e
{
- \cs_new:Npn \exp_not:N \@@_change_case_math_space:nnNw #1#2#3
+ \cs_new:Npn \exp_not:N \@@_change_case_math_space:nnnNw #1#2#3#4
\c_space_tl
}
{
\@@_change_case_store:n { ~ }
- \@@_change_case_math_loop:nnNw {#1} {#2} #3
+ \@@_change_case_math_loop:nnnNw {#1} {#2} {#3} #4
}
% \end{macrocode}
% Once potential math-mode cases are filtered out the next stage is to
% test if the token grabbed is a control sequence: the two routes the code
% may take are then very different.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_cs_check:nnN #1#2#3
+\cs_new:Npn \@@_change_case_cs_check:nnnN #1#2#3#4
{
- \token_if_cs:NTF #3
- { \@@_change_case_exclude:nnN {#1} {#2} }
+ \token_if_cs:NTF #4
+ { \@@_change_case_exclude:nnnN {#1} {#2} {#3} }
{
\@@_codepoint_process:nN
- { \use:c { @@_change_case_custom_ #1 :nnn } {#1} {#2} }
+ { \use:c { @@_change_case_custom_ #1 :nnnn } {#1} {#2} {#3} }
}
- #3
+ #4
}
% \end{macrocode}
% To deal with a control sequence there is first a need to test if it is
@@ -457,92 +460,115 @@
% done using a loop as for the other special cases. If a hit is found then
% the argument is grabbed and passed through as-is.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_exclude:nnN #1#2#3
+\cs_new:Npn \@@_change_case_exclude:nnnN #1#2#3#4
{
- \exp_args:Ne \@@_change_case_exclude:nnnN
+ \exp_args:Ne \@@_change_case_exclude:nnnnN
{
\exp_not:V \l_text_math_arg_tl
\exp_not:V \l_text_case_exclude_arg_tl
}
- {#1} {#2} #3
+ {#1} {#2} {#3} #4
}
-\cs_new:Npn \@@_change_case_exclude:nnnN #1#2#3#4
+\cs_new:Npn \@@_change_case_exclude:nnnnN #1#2#3#4#5
{
- \@@_change_case_exclude:nnNN {#2} {#3} #4 #1
+ \@@_change_case_exclude:nnnNN {#2} {#3} {#4} #5 #1
\q_@@_recursion_tail \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_exclude:nnNN #1#2#3#4
+\cs_new:Npn \@@_change_case_exclude:nnnNN #1#2#3#4#5
{
- \@@_if_q_recursion_tail_stop_do:Nn #4
- { \@@_change_case_replace:nnN {#1} {#2} #3 }
- \str_if_eq:nnTF {#3} {#4}
+ \@@_if_q_recursion_tail_stop_do:Nn #5
+ { \@@_change_case_replace:nnnN {#1} {#2} {#3} #4 }
+ \str_if_eq:nnTF {#4} {#5}
{
\@@_use_i_delimit_by_q_recursion_stop:nw
- { \@@_change_case_exclude:nnNw {#1} {#2} #3 }
+ { \@@_change_case_exclude:nnnNw {#1} {#2} {#3} #4 }
}
- { \@@_change_case_exclude:nnNN {#1} {#2} #3 }
+ { \@@_change_case_exclude:nnnNN {#1} {#2} {#3} #4 }
}
-\cs_new:Npn \@@_change_case_exclude:nnNw #1#2#3#4#
- { \@@_change_case_exclude:nnNnn {#1} {#2} {#3} {#4} }
-\cs_new:Npn \@@_change_case_exclude:nnNnn #1#2#3#4#5
+\cs_new:Npn \@@_change_case_exclude:nnnNw #1#2#3#4#5#
+ { \@@_change_case_exclude:nnnNnn {#1} {#2} {#3} {#4} {#5} }
+\cs_new:Npn \@@_change_case_exclude:nnnNnn #1#2#3#4#5#6
{
- \tl_if_blank:nTF {#4}
- { \@@_change_case_store:n { #3 {#5} } }
+ \tl_if_blank:nTF {#5}
+ { \@@_change_case_store:n { #4 {#6} } }
{
\@@_change_case_store:o
{
- \exp_after:wN #3
- \exp:w \@@_change_case_auxii:nnn {#4} {#1} {#2}
- {#5}
+ \exp_after:wN #4
+ \exp:w \@@_change_case_auxii:nnnn {#5} {#1} {#2} {#3}
+ {#6}
}
}
- \@@_change_case_loop:nnw {#1} {#2}
+ \@@_change_case_loop:nnnw {#1} {#2} {#3}
}
% \end{macrocode}
% Deal with any specialist replacement for case changing.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_replace:nnN #1#2#3
+\cs_new:Npn \@@_change_case_replace:nnnN #1#2#3#4
{
- \cs_if_exist:cTF { l_@@_case_ \token_to_str:N #3 _tl }
+ \cs_if_exist:cTF { l_@@_case_ \token_to_str:N #4 _tl }
{
- \@@_change_case_replace:vnn
- { l_@@_case_ \token_to_str:N #3 _tl } {#1} {#2}
+ \@@_change_case_replace:vnnn
+ { l_@@_case_ \token_to_str:N #4 _tl } {#1} {#2} {#3}
}
- { \@@_change_case_switch:nnN {#1} {#2} #3 }
+ { \@@_change_case_switch:nnnN {#1} {#2} {#3} #4 }
}
-\cs_new:Npn \@@_change_case_replace:nnn #1#2#3
- { \@@_change_case_loop:nnw {#2} {#3} #1 }
-\cs_generate_variant:Nn \@@_change_case_replace:nnn { v }
+\cs_new:Npn \@@_change_case_replace:nnnn #1#2#3#4
+ { \@@_change_case_loop:nnnw {#2} {#3} {#4} #1 }
+\cs_generate_variant:Nn \@@_change_case_replace:nnnn { v }
% \end{macrocode}
% Allow for manually-controlled case switching.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_switch:nnN #1#2#3
+\cs_new:Npn \@@_change_case_switch:nnnN #1#2#3#4
+ {
+ \cs_if_eq:NNTF #4 \text_case_switch:nnnn
+ { \use:c { @@_change_case_switch_ #1 :nnnNnnnn } }
+ { \use:c { @@_change_case_letterlike_ #1 :nnnN } }
+ {#1} {#2} {#3} #4
+ }
+\cs_new:Npn \@@_change_case_switch_lower:nnnNnnnn #1#2#3#4#5#6#7#8
{
- \cs_if_eq:NNTF #3 \text_case_switch:nnnn
- { \use:c { @@_change_case_switch_ #1 :nnNnnnn } }
- { \use:c { @@_change_case_letterlike_ #1 :nnN } }
- {#1} {#2} #3
+ \@@_change_case_store:n {#7}
+ \@@_change_case_loop:nnnw {#1} {#2} {#3}
}
-\cs_new:Npn \@@_change_case_switch_lower:nnNnnnn #1#2#3#4#5#6#7
+\cs_new:Npn \@@_change_case_switch_upper:nnnNnnnn #1#2#3#4#5#6#7#8
{
\@@_change_case_store:n {#6}
- \@@_change_case_loop:nnw {#1} {#2}
+ \@@_change_case_loop:nnnw {#1} {#2} {#3}
}
-\cs_new:Npn \@@_change_case_switch_upper:nnNnnnn #1#2#3#4#5#6#7
+\cs_new:Npn \@@_change_case_switch_title:nnnNnnnn #1#2#3#4#5#6#7#8
{
- \@@_change_case_store:n {#5}
- \@@_change_case_loop:nnw {#1} {#2}
+ \@@_change_case_store:n {#8}
+ \@@_change_case_skip:nnw {#2} {#3}
}
-\cs_new:Npn \@@_change_case_switch_title:nnNnnnn #1#2#3#4#5#6#7
+% \end{macrocode}
+% Skip over material quickly after titlecase-first-only initials
+% \begin{macrocode}
+\cs_new:Npn \@@_change_case_skip:nnw #1#2#3 \q_@@_recursion_stop
{
- \@@_change_case_store:n {#7}
- \@@_change_case_loop:nnw {#1} {#2}
+ \tl_if_head_is_N_type:nTF {#3}
+ { \@@_change_case_skip_N_type:nnN }
+ {
+ \tl_if_head_is_group:nTF {#3}
+ { \@@_change_case_skip_group:nnn }
+ { \@@_change_case_skip_space:nnw }
+ }
+ {#1} {#2} #3 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_switch_titleonly:nnNnnnn #1#2#3#4#5#6#7
+\cs_new:Npn \@@_change_case_skip_N_type:nnN #1#2#3
{
- \@@_change_case_store:n {#7}
- \@@_change_case_break:w
+ \@@_if_q_recursion_tail_stop_do:Nn #3
+ { \@@_change_case_end:w }
+ \@@_change_case_store:n {#3}
+ \@@_change_case_skip:nnw {#1} {#2}
+ }
+\cs_new:Npn \@@_change_case_skip_group:nnn #1#2#3
+ {
+ \@@_change_case_store:n { {#3} }
+ \@@_change_case_skip:nnw {#1} {#2}
}
+\cs_new:Npn \@@_change_case_skip_space:nnw #1#2
+ { \@@_change_case_space:nnnw {#1} {#1} {#2} }
% \end{macrocode}
% Letter-like commands may still be present: they are set up using a simple
% lookup approach, so can easily be handled with no loop. If there is no
@@ -550,68 +576,64 @@
% are all available only in upper- and lowercase, so titlecasing maps to the
% uppercase version.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_letterlike_lower:nnN #1#2#3
- { \@@_change_case_letterlike:nnnnN {#1} {#1} {#1} {#2} #3 }
-\cs_new_eq:NN \@@_change_case_letterlike_upper:nnN
- \@@_change_case_letterlike_lower:nnN
-\cs_new:Npn \@@_change_case_letterlike_title:nnN #1#2#3
- { \@@_change_case_letterlike:nnnnN { upper } { lower } {#1} {#2} #3 }
-\cs_new:Npn \@@_change_case_letterlike_titleonly:nnN #1#2#3
- { \@@_change_case_letterlike:nnnnN { upper } { end } {#1} {#2} #3 }
-\cs_new:Npn \@@_change_case_letterlike:nnnnN #1#2#3#4#5
- {
- \cs_if_exist:cTF { c_@@_ #1 case_ \token_to_str:N #5 _tl }
+\cs_new:Npn \@@_change_case_letterlike_lower:nnnN #1#2#3#4
+ { \@@_change_case_letterlike:nnnnnN {#1} {#1} {#1} {#2} {#3} #4 }
+\cs_new_eq:NN \@@_change_case_letterlike_upper:nnnN
+ \@@_change_case_letterlike_lower:nnnN
+\cs_new:Npn \@@_change_case_letterlike_title:nnnN #1#2#3#4
+ { \@@_change_case_letterlike:nnnnnN { upper } { end } {#1} {#2} {#3} #4 }
+\cs_new:Npn \@@_change_case_letterlike:nnnnnN #1#2#3#4#5#6
+ {
+ \cs_if_exist:cTF { c_@@_ #1 case_ \token_to_str:N #6 _tl }
{
\@@_change_case_store:v
- { c_@@_ #1 case_ \token_to_str:N #5 _tl }
- \use:c { @@_change_case_next_ #2 :nn } {#2} {#4}
+ { c_@@_ #1 case_ \token_to_str:N #6 _tl }
+ \use:c { @@_change_case_next_ #2 :nnn } {#2} {#4} {#5}
}
{
- \@@_change_case_store:n {#5}
+ \@@_change_case_store:n {#6}
\cs_if_exist:cTF
{
c_@@_
\str_if_eq:nnTF {#1} { lower } { upper } { lower }
- case_ \token_to_str:N #5 _tl
+ case_ \token_to_str:N #6 _tl
}
- { \use:c { @@_change_case_next_ #2 :nn } {#2} {#4} }
- { \@@_change_case_loop:nnw {#3} {#4} }
+ { \use:c { @@_change_case_next_ #2 :nnn } {#2} {#4} {#5} }
+ { \@@_change_case_loop:nnnw {#3} {#4} {#5} }
}
}
% \end{macrocode}
% Check for a customised codepoint result.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_custom_lower:nnn #1#2#3
+\cs_new:Npn \@@_change_case_custom_lower:nnnn #1#2#3#4
{
- \@@_change_case_custom:nnnnn {#1} {#2} {#3} {#1}
- { \use:c { @@_change_case_codepoint_ #1 :nnn } {#1} {#2} {#3} }
+ \@@_change_case_custom:nnnnnn {#1} {#1} {#2} {#3} {#4}
+ { \use:c { @@_change_case_codepoint_ #1 :nnnn } {#1} {#2} {#3} {#4} }
}
-\cs_new_eq:NN \@@_change_case_custom_upper:nnn
- \@@_change_case_custom_lower:nnn
-\cs_new:Npn \@@_change_case_custom_title:nnn #1#2#3
+\cs_new_eq:NN \@@_change_case_custom_upper:nnnn
+ \@@_change_case_custom_lower:nnnn
+\cs_new:Npn \@@_change_case_custom_title:nnnn #1#2#3#4
{
- \@@_change_case_custom:nnnnn { title } {#2} {#3} {#1}
+ \@@_change_case_custom:nnnnnn { title } {#1} {#2} {#3} {#4}
{
- \@@_change_case_custom:nnnnn { upper } {#2} {#3} {#1}
- { \use:c { @@_change_case_codepoint_ #1 :nnn } {#1} {#2} {#3} }
+ \@@_change_case_custom:nnnnnn { upper } {#1} {#2} {#3} {#4}
+ { \use:c { @@_change_case_codepoint_ #1 :nnnn } {#1} {#2} {#3} {#4} }
}
}
-\cs_new_eq:NN \@@_change_case_custom_titleonly:nnn
- \@@_change_case_custom_title:nnn
-\cs_new:Npn \@@_change_case_custom:nnnnn #1#2#3#4#5
+\cs_new:Npn \@@_change_case_custom:nnnnnn #1#2#3#4#5#6
{
- \tl_if_exist:cTF { l_@@_ #1 case _ \tl_to_str:n {#3} _ #2 _tl }
+ \tl_if_exist:cTF { l_@@_ #1 case _ \tl_to_str:n {#5} _ #4 _tl }
{
- \@@_change_case_replace:vnn
- { l_@@_ #1 case _ \tl_to_str:n {#3} _ #2 _tl } {#4} {#2}
+ \@@_change_case_replace:vnnn
+ { l_@@_ #1 case _ \tl_to_str:n {#5} _ #4 _tl } {#2} {#3} {#4}
}
{
- \tl_if_exist:cTF { l_@@_ #1 case _ \tl_to_str:n {#3} _tl }
+ \tl_if_exist:cTF { l_@@_ #1 case _ \tl_to_str:n {#5} _tl }
{
- \@@_change_case_replace:vnn
- { l_@@_ #1 case _ \tl_to_str:n {#3} _tl } {#4} {#2}
+ \@@_change_case_replace:vnnn
+ { l_@@_ #1 case _ \tl_to_str:n {#5} _tl } {#2} {#3} {#4}
}
- {#5}
+ {#6}
}
}
% \end{macrocode}
@@ -620,17 +642,17 @@
% is there the special case of a terminal sigma. If not, then we pass to
% a simple codepoint mapping.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_codepoint_lower:nnn #1#2#3
+\cs_new:Npn \@@_change_case_codepoint_lower:nnnn #1#2#3#4
{
- \cs_if_exist_use:cF { @@_change_case_lower_ #2 :nnnn }
- { \@@_change_case_lower_sigma:nnnn }
- {#1} {#1} {#2} {#3}
+ \cs_if_exist_use:cF { @@_change_case_lower_ #3 :nnnnn }
+ { \@@_change_case_lower_sigma:nnnnn }
+ {#1} {#1} {#2} {#3} {#4}
}
-\cs_new:Npn \@@_change_case_codepoint_upper:nnn #1#2#3
+\cs_new:Npn \@@_change_case_codepoint_upper:nnnn #1#2#3#4
{
- \cs_if_exist_use:cF { @@_change_case_upper_ #2 :nnnn }
- { \@@_change_case_codepoint:nnnn }
- {#1} {#1} {#2} {#3}
+ \cs_if_exist_use:cF { @@_change_case_upper_ #3 :nnnnn }
+ { \@@_change_case_codepoint:nnnnn }
+ {#1} {#1} {#2} {#3} {#4}
}
% \end{macrocode}
% If the current character is an uppercase sigma, the a check is made on the
@@ -638,91 +660,87 @@
% then there is a look-ahead phase: the logic here is simply based on letters
% or actives (to cover $8$-bit engines).
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_lower_sigma:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_lower_sigma:nnnnn #1#2#3#4#5
{
- \@@_codepoint_compare:nNnTF {#4} = { "03A3 }
- { \@@_change_case_lower_sigma:nnnw {#2} }
- { \@@_change_case_codepoint:nnnn {#1} {#2} }
- {#3} {#4}
+ \@@_codepoint_compare:nNnTF {#5} = { "03A3 }
+ { \@@_change_case_lower_sigma:nnnnw {#2} }
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} }
+ {#3} {#4} {#5}
}
-\cs_new:Npn \@@_change_case_lower_sigma:nnnw #1#2#3#4 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_lower_sigma:nnnnw #1#2#3#4#5 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_lower_sigma:nnnN {#3} }
+ \tl_if_head_is_N_type:nTF {#5}
+ { \@@_change_case_lower_sigma:nnnnN {#4} }
{
\@@_change_case_store:e
- { \codepoint_generate:nn { "03C2 } { \@@_char_catcode:N #3 } }
- \@@_change_case_loop:nnw
+ { \codepoint_generate:nn { "03C2 } { \@@_char_catcode:N #4 } }
+ \@@_change_case_loop:nnnw
}
- {#1} {#2} #4 \q_@@_recursion_stop
+ {#1} {#2} {#3} #5 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_lower_sigma:nnnN #1#2#3#4
+\cs_new:Npn \@@_change_case_lower_sigma:nnnnN #1#2#3#4#5
{
\@@_change_case_store:e
{
\bool_lazy_or:nnTF
- { \token_if_letter_p:N #4 }
+ { \token_if_letter_p:N #5 }
{
\bool_lazy_and_p:nn
- { \token_if_active_p:N #4 }
- { \int_compare_p:nNn {`#4} > { "80 } }
+ { \token_if_active_p:N #5 }
+ { \int_compare_p:nNn {`#5} > { "80 } }
}
{ \codepoint_generate:nn { "03C3 } { \@@_char_catcode:N #1 } }
{ \codepoint_generate:nn { "03C2 } { \@@_char_catcode:N #1 } }
}
- \@@_change_case_loop:nnw {#2} {#3} #4
+ \@@_change_case_loop:nnnw {#2} {#3} {#4} #5
}
% \end{macrocode}
% For titlecasing, we need to fully expand the new character to see if it
% is a letter (or active).
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_codepoint_title:nnn #1#2#3
+\cs_new:Npn \@@_change_case_codepoint_title:nnnn #1#2#3#4
{
\bool_if:NTF \l_text_titlecase_check_letter_bool
{
- \tl_if_single:nTF {#3}
+ \tl_if_single:nTF {#4}
{
\bool_lazy_or:nnTF
- { \token_if_letter_p:N #3 }
+ { \token_if_letter_p:N #4 }
{
\bool_lazy_and_p:nn
- { \token_if_active_p:N #3 }
- { ! \int_compare_p:nNn {`#3} < { "80 } }
+ { \token_if_active_p:N #4 }
+ { ! \int_compare_p:nNn {`#4} < { "80 } }
}
- { \use:c { @@_change_case_codepoint_ #1 :nn } }
- { \@@_change_case_codepoint_title:nnnn { title } {#1} }
+ { \@@_change_case_codepoint_title:nnn }
+ { \@@_change_case_codepoint_title:nnnnn { title } {#1} }
}
- { \use:c { @@_change_case_codepoint_ #1 :nn } }
+ { \@@_change_case_codepoint_title:nnn }
}
- { \use:c { @@_change_case_codepoint_ #1 :nn } }
- {#2} {#3}
+ { \@@_change_case_codepoint_title:nnn }
+ {#2} {#3} {#4}
}
-\cs_new_eq:NN \@@_change_case_codepoint_titleonly:nnn
- \@@_change_case_codepoint_title:nnn
-\cs_new:Npn \@@_change_case_codepoint_title:nn #1#2
- { \@@_change_case_codepoint_title:nnnn { title } { lower } {#1} {#2} }
-\cs_new:Npn \@@_change_case_codepoint_titleonly:nn #1#2
- { \@@_change_case_codepoint_title:nnnn { title } { end } {#1} {#2} }
-\cs_new:Npn \@@_change_case_codepoint_title:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_codepoint_title:nnn #1#2#3
+ { \@@_change_case_codepoint_title:nnnnn { title } { end } {#1} {#2} {#3} }
+\cs_new:Npn \@@_change_case_codepoint_title:nnnnn #1#2#3#4#5
{
- \cs_if_exist_use:cF { @@_change_case_title_ #3 :nnnn }
+ \cs_if_exist_use:cF { @@_change_case_title_ #4 :nnnnn }
{
- \cs_if_exist_use:cF { @@_change_case_upper_ #3 :nnnn }
- { \@@_change_case_codepoint:nnnn }
+ \cs_if_exist_use:cF { @@_change_case_upper_ #4 :nnnnn }
+ { \@@_change_case_codepoint:nnnnn }
}
- {#1} {#2} {#3} {#4}
+ {#1} {#2} {#3} {#4} {#5}
}
-\cs_new:Npn \@@_change_case_codepoint:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_codepoint:nnnnn #1#2#3#4#5
{
\bool_lazy_and:nnTF
- { \tl_if_single_p:n {#4} }
- { \token_if_active_p:N #4 }
- { \@@_change_case_store:n {#4} }
+ { \tl_if_single_p:n {#5} }
+ { \token_if_active_p:N #5 }
+ { \@@_change_case_store:n {#5} }
{
\@@_change_case_store:e
- { \@@_change_case_codepoint:nn {#1} {#4} }
+ { \@@_change_case_codepoint:nn {#1} {#5} }
}
- \use:c { @@_change_case_next_ #2 :nn } {#2} {#3}
+ \use:c { @@_change_case_next_ #2 :nnn } {#2} {#3} {#4}
}
\cs_new:Npn \@@_change_case_codepoint:nn #1#2
{
@@ -799,16 +817,14 @@
}
}
}
-\cs_new:Npn \@@_change_case_next_lower:nn #1#2
- { \@@_change_case_loop:nnw {#1} {#2} }
-\cs_new_eq:NN \@@_change_case_next_upper:nn
- \@@_change_case_next_lower:nn
-\cs_new_eq:NN \@@_change_case_next_title:nn
- \@@_change_case_next_lower:nn
-\cs_new_eq:NN \@@_change_case_next_titleonly:nn
- \@@_change_case_next_lower:nn
-\cs_new:Npn \@@_change_case_next_end:nn #1#2
- { \@@_change_case_break:w }
+\cs_new:Npn \@@_change_case_next_lower:nnn #1#2#3
+ { \@@_change_case_loop:nnnw {#1} {#2} {#3} }
+\cs_new_eq:NN \@@_change_case_next_upper:nnn
+ \@@_change_case_next_lower:nnn
+\cs_new_eq:NN \@@_change_case_next_title:nnn
+ \@@_change_case_next_lower:nnn
+\cs_new:Npn \@@_change_case_next_end:nnn #1#2#3
+ { \@@_change_case_skip:nnw {#2} {#3} }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -853,6 +869,13 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
%
% \begin{macro}{\text_declare_case_equivalent:Nn}
% Create equivalents to allow replacement.
@@ -914,6 +937,7 @@
{
\tl_clear_new:c { l_@@_ #2 case _ #1 _ #3 _tl }
\tl_set:cn { l_@@_ #2 case _ #1 _ #3 _ tl } {#4}
+ \tl_clear_new:c { l_@@_ #2 case_special_ #3 _tl }
}
% \end{macrocode}
% \end{macro}
@@ -944,55 +968,58 @@
% \end{macro}
%
% \begin{macro}[EXP]
-% {\@@_change_case_upper_de-x-eszett:nnnn, \@@_change_case_upper_de-alt:nnnn}
+% {
+% \@@_change_case_upper_de-x-eszett:nnnnn,
+% \@@_change_case_upper_de-alt:nnnnn
+% }
% A simple alternative version for German.
% \begin{macrocode}
-\cs_new:cpn { @@_change_case_upper_de-x-eszett:nnnn } #1#2#3#4
+\cs_new:cpn { @@_change_case_upper_de-x-eszett:nnnnn } #1#2#3#4#5
{
- \@@_codepoint_compare:nNnTF {#4} = { "00DF }
+ \@@_codepoint_compare:nNnTF {#5} = { "00DF }
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "1E9E }
- { \@@_change_case_catcode:nn {#4} { "1E9E } }
+ { \@@_change_case_catcode:nn {#5} { "1E9E } }
}
- \use:c { @@_change_case_next_ #2 :nn }
- {#2} {#3}
+ \use:c { @@_change_case_next_ #2 :nnn }
+ {#2} {#3} {#4}
}
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
}
-\cs_new_eq:cc { @@_change_case_upper_de-alt:nnnn }
- { @@_change_case_upper_de-x-eszett:nnnn }
+\cs_new_eq:cc { @@_change_case_upper_de-alt:nnnnn }
+ { @@_change_case_upper_de-x-eszett:nnnnn }
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]
% {
-% \@@_change_case_upper_el:nnnn ,
-% \@@_change_case_upper_el_aux:nnnn ,
-% \@@_change_case_upper_el-x-iota:nnnn
+% \@@_change_case_upper_el:nnnnn ,
+% \@@_change_case_upper_el-x-iota:nnnnn ,
+% \@@_change_case_upper_el_aux:nnnnn
% }
-% \begin{macro}[EXP]{\@@_change_case_upper_el:nnn}
-% \begin{macro}[EXP]{\@@_change_case_upper_el:nnnw}
+% \begin{macro}[EXP]{\@@_change_case_upper_el:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_upper_el:nnnnw}
% \begin{macro}[EXP]
-% {\@@_change_case_upper_el:nnnN, \@@_change_case_upper_el_aux:nnnN}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnw}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnN}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnn}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_dialytika:nnn}
+% {\@@_change_case_upper_el:nnnnN, \@@_change_case_upper_el_aux:nnnnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnnw}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:nnnnnnn}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_dialytika:nnnn}
% \begin{macro}[EXP]{\@@_change_case_upper_el_dialytika:n}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnw}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnN}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnnw}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnnnn}
% \begin{macro}[EXP]
% {
% \@@_change_case_upper_el_ypogegrammeni:n ,
% \@@_change_case_upper_el-x-iota_ypogegrammeni:n
% }
% \begin{macro}[EXP]{\@@_change_case_upper_el_stress:nn}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnw}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnN}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnn}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnnw}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnnn}
% \begin{macro}[EXP,noTF]
% {
% \@@_change_case_if_greek:n ,
@@ -1017,65 +1044,65 @@
% for \pdfTeX{} so is best left unchanged, and the latter has issues concerning
% how \texttt{LGR} outputs the input and output (differently!).
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_upper_el:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_el:nnnnn #1#2#3#4#5
{
\bool_lazy_and:nnTF
- { \@@_change_case_if_greek_p:n {#4} }
+ { \@@_change_case_if_greek_p:n {#5} }
{
! \bool_lazy_or_p:nn
- { \@@_codepoint_compare_p:nNn {#4} = { "0374 } }
- { \@@_codepoint_compare_p:nNn {#4} = { "037E } }
+ { \@@_codepoint_compare_p:nNn {#5} = { "0374 } }
+ { \@@_codepoint_compare_p:nNn {#5} = { "037E } }
}
{
- \@@_change_case_if_greek_spacing_diacritic:nTF {#4}
+ \@@_change_case_if_greek_spacing_diacritic:nTF {#5}
{
- \@@_change_case_store:n {#4}
- \@@_change_case_loop:nnw
+ \@@_change_case_store:n {#5}
+ \@@_change_case_loop:nnnw
}
{
- \exp_args:Ne \@@_change_case_upper_el:nnn
+ \exp_args:Ne \@@_change_case_upper_el:nnnn
{
\codepoint_to_nfd:n
- { \@@_codepoint_from_chars:Nw #4 }
+ { \@@_codepoint_from_chars:Nw #5 }
}
}
- {#2} {#3}
+ {#2} {#3} {#4}
}
{
- \@@_codepoint_compare:nNnTF {#4} = { "0345 }
+ \@@_codepoint_compare:nNnTF {#5} = { "0345 }
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0399 }
{ \char_value_catcode:n { "0399 } }
}
- \@@_change_case_loop:nnw {#2} {#3}
+ \@@_change_case_loop:nnnw {#2} {#3} {#4}
}
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
}
}
-\cs_new_eq:cN { @@_change_case_upper_el-x-iota:nnnn }
- \@@_change_case_upper_el:nnnn
-\cs_new:Npn \@@_change_case_upper_el:nnn #1#2#3
+\cs_new_eq:cN { @@_change_case_upper_el-x-iota:nnnnn }
+ \@@_change_case_upper_el:nnnnn
+\cs_new:Npn \@@_change_case_upper_el:nnnn #1#2#3#4
{
\@@_codepoint_process:nN
- { \@@_change_case_upper_el:nnnw {#2} {#3} } #1
+ { \@@_change_case_upper_el:nnnnw {#2} {#3} {#4} } #1
}
% \end{macrocode}
% At this stage we have the first NFD codepoint as |#3|. What we need to know
% is whether after that we have another character, either from the NFD or
% directly in the input. If not, we store the changed character at this stage.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_upper_el:nnnw #1#2#3#4 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_upper_el:nnnnw #1#2#3#4#5 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_upper_el:nnnN {#3} }
+ \tl_if_head_is_N_type:nTF {#5}
+ { \@@_change_case_upper_el:nnnnN {#4} }
{
\@@_change_case_store:e
- { \@@_change_case_codepoint:nn { upper } {#3} }
- \@@_change_case_loop:nnw
+ { \@@_change_case_codepoint:nn { upper } {#4} }
+ \@@_change_case_loop:nnnw
}
- {#1} {#2} #4 \q_@@_recursion_stop
+ {#1} {#2} {#3} #5 \q_@@_recursion_stop
}
% \end{macrocode}
% Now, we check the detail of the next codepoint: again we filter out the
@@ -1085,99 +1112,99 @@
% to move any ypogegrammeni to after accents (in case the input is not
% normalised). The ypogegrammeni itself is handled separately.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_upper_el:nnnN #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_el:nnnnN #1#2#3#4#5
{
- \token_if_cs:NTF #4
+ \token_if_cs:NTF #5
{
\@@_change_case_store:e
{ \@@_change_case_codepoint:nn { upper } {#1} }
- \@@_change_case_loop:nnw {#2} {#3} #4
+ \@@_change_case_loop:nnnw {#2} {#3} {#4} #5
}
{
\@@_change_case_if_takes_ypogegrammeni:nTF {#1}
{
- \@@_change_case_upper_el_ypogegrammeni:nnnnnw
- {#1} {#2} {#3} { } { } #4
+ \@@_change_case_upper_el_ypogegrammeni:nnnnnnw
+ {#1} {#2} {#3} {#4} { } { } #5
}
- { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4 }
+ { \@@_change_case_upper_el_aux:nnnnN {#1} {#2} {#3} {#4} #5 }
}
}
-\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnw
- #1#2#3#4#5#6 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnnw
+ #1#2#3#4#5#6#7 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#6}
+ \tl_if_head_is_N_type:nTF {#7}
{
- \@@_change_case_upper_el_ypogegrammeni:nnnnnN
- {#1} {#2} {#3} {#4} {#5}
+ \@@_change_case_upper_el_ypogegrammeni:nnnnnnN
+ {#1} {#2} {#3} {#4} {#5} {#6}
}
- { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4#5 }
- #6 \q_@@_recursion_stop
+ { \@@_change_case_upper_el_aux:nnnnN {#1} {#2} {#3} {#4} #5#6 }
+ #7 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnN #1#2#3#4#5#6
+\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnnN #1#2#3#4#5#6#7
{
- \token_if_cs:NTF #6
- { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4#5 }
+ \token_if_cs:NTF #7
+ { \@@_change_case_upper_el_aux:nnnnN {#1} {#2} {#3} {#4} #5#6 }
{
\@@_codepoint_process:nN
{
- \@@_change_case_upper_el_ypogegrammeni:nnnnnn
- {#1} {#2} {#3} {#4} {#5}
+ \@@_change_case_upper_el_ypogegrammeni:nnnnnnn
+ {#1} {#2} {#3} {#4} {#5} {#6}
}
}
- #6
+ #7
}
-\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnn #1#2#3#4#5#6
+\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnnn #1#2#3#4#5#6#7
{
- \@@_codepoint_compare:nNnTF {#6} = { "0345 }
+ \@@_codepoint_compare:nNnTF {#7} = { "0345 }
{
- \@@_change_case_upper_el_ypogegrammeni:nnnnnw
- {#1} {#2} {#3} {#4} {#6}
+ \@@_change_case_upper_el_ypogegrammeni:nnnnnnw
+ {#1} {#2} {#3} {#4} {#5} {#7}
}
{
\bool_lazy_or:nnTF
- { \@@_change_case_if_greek_accent_p:n {#6} }
- { \@@_change_case_if_greek_breathing_p:n {#6} }
+ { \@@_change_case_if_greek_accent_p:n {#7} }
+ { \@@_change_case_if_greek_breathing_p:n {#7} }
{
- \@@_change_case_upper_el_ypogegrammeni:nnnnnw
- {#1} {#2} {#3} {#4#6} {#5}
+ \@@_change_case_upper_el_ypogegrammeni:nnnnnnw
+ {#1} {#2} {#3} {#4} {#5#7} {#6}
}
- { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4#5 #6 }
+ { \@@_change_case_upper_el_aux:nnnnN {#1} {#2} {#3} {#4} #5#6 #7 }
}
}
-\cs_new:Npn \@@_change_case_upper_el_aux:nnnN #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_el_aux:nnnnN #1#2#3#4#5
{
\@@_codepoint_process:nN
- { \@@_change_case_upper_el_aux:nnnn {#1} {#2} {#3} } #4
+ { \@@_change_case_upper_el_aux:nnnnn {#1} {#2} {#3} {#4} } #5
}
-\cs_new:Npn \@@_change_case_upper_el_aux:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_el_aux:nnnnn #1#2#3#4#5
{
- \@@_codepoint_compare:nNnTF {#4} = { "0308 }
- { \@@_change_case_upper_el_dialytika:nnn {#2} {#3} {#1} }
+ \@@_codepoint_compare:nNnTF {#5} = { "0308 }
+ { \@@_change_case_upper_el_dialytika:nnnn {#2} {#3} {#4} {#1} }
{
- \@@_change_case_if_greek_accent:nTF {#4}
- { \@@_change_case_upper_el_hiatus:nnnw {#2} {#3} {#1} }
+ \@@_change_case_if_greek_accent:nTF {#5}
+ { \@@_change_case_upper_el_hiatus:nnnnw {#2} {#3} {#4} {#1} }
{
- \@@_change_case_if_greek_breathing:nTF {#4}
- { \@@_change_case_upper_el:nnn {#1} {#2} {#3} }
+ \@@_change_case_if_greek_breathing:nTF {#5}
+ { \@@_change_case_upper_el:nnnn {#1} {#2} {#3} {#4} }
{
- \@@_codepoint_compare:nNnTF {#4} = { "0345 }
+ \@@_codepoint_compare:nNnTF {#5} = { "0345 }
{
\@@_change_case_store:e
- { \use:c { @@_change_case_upper_ #3 _ypogegrammeni:n } {#1} }
- \@@_change_case_loop:nnw {#2} {#3}
+ { \use:c { @@_change_case_upper_ #4 _ypogegrammeni:n } {#1} }
+ \@@_change_case_loop:nnnw {#2} {#3} {#4}
}
{
- \@@_change_case_if_greek_stress:nTF {#4}
+ \@@_change_case_if_greek_stress:nTF {#5}
{
\@@_change_case_store:e
- { \@@_change_case_upper_el_stress:nn {#1} {#4} }
- \@@_change_case_loop:nnw {#2} {#3}
+ { \@@_change_case_upper_el_stress:nn {#1} {#5} }
+ \@@_change_case_loop:nnnw {#2} {#3} {#4}
}
{
\@@_change_case_store:e
{ \@@_change_case_codepoint:nn { upper } {#1} }
- \@@_change_case_loop:nnw {#2} {#3} #4
+ \@@_change_case_loop:nnnw {#2} {#3} {#4} #5
}
}
}
@@ -1189,15 +1216,15 @@
% We know only two letters take it, so we can shortcut here on the second
% part of the tests.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_upper_el_dialytika:nnn #1#2#3
+\cs_new:Npn \@@_change_case_upper_el_dialytika:nnnn #1#2#3#4
{
- \@@_change_case_if_takes_dialytika:nTF {#3}
- { \@@_change_case_upper_el_dialytika:n {#3} }
+ \@@_change_case_if_takes_dialytika:nTF {#4}
+ { \@@_change_case_upper_el_dialytika:n {#4} }
{
\@@_change_case_store:e
- { \@@_change_case_codepoint:nn { upper } {#3} }
+ { \@@_change_case_codepoint:nn { upper } {#4} }
}
- \@@_change_case_upper_el_gobble:nnw {#1} {#2}
+ \@@_change_case_upper_el_gobble:nnnw {#1} {#2} {#3}
}
\cs_new:Npn \@@_change_case_upper_el_dialytika:n #1
{
@@ -1220,41 +1247,41 @@
% Adding a hiatus needs some of the same ideas, but if there is not one we
% skip this code point, hence needing a separate function.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnw
- #1#2#3#4 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnnw
+ #1#2#3#4#5 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_upper_el_hiatus:nnnN {#3} }
+ \tl_if_head_is_N_type:nTF {#5}
+ { \@@_change_case_upper_el_hiatus:nnnnN {#4} }
{
\@@_change_case_store:e
- { \@@_change_case_codepoint:nn { upper } {#3} }
- \@@_change_case_loop:nnw
+ { \@@_change_case_codepoint:nn { upper } {#4} }
+ \@@_change_case_loop:nnnw
}
- {#1} {#2} #4 \q_@@_recursion_stop
+ {#1} {#2} {#3} #5 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnN #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnnN #1#2#3#4#5
{
- \token_if_cs:NTF #4
+ \token_if_cs:NTF #5
{
\@@_change_case_store:e
{ \@@_change_case_codepoint:nn { upper } {#1} }
- \@@_change_case_loop:nnw {#2} {#3} #4
+ \@@_change_case_loop:nnnw {#2} {#3} {#4} #5
}
{
\@@_codepoint_process:nN
- { \@@_change_case_upper_el_hiatus:nnnn {#1} {#2} {#3} } #4
+ { \@@_change_case_upper_el_hiatus:nnnnn {#1} {#2} {#3} {#4} } #5
}
}
-\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_el_hiatus:nnnnn #1#2#3#4#5
{
- \@@_change_case_if_takes_dialytika:nTF {#4}
+ \@@_change_case_if_takes_dialytika:nTF {#5}
{
\@@_change_case_store:e
{ \@@_change_case_codepoint:nn { upper } {#1} }
- \@@_change_case_upper_el_dialytika:n {#4}
- \@@_change_case_upper_el_gobble:nnw {#2} {#3}
+ \@@_change_case_upper_el_dialytika:n {#5}
+ \@@_change_case_upper_el_gobble:nnnw {#2} {#3} {#4}
}
- { \@@_change_case_upper_el:nnn {#1} {#2} {#3} #4 }
+ { \@@_change_case_upper_el:nnnn {#1} {#2} {#3} {#4} #5 }
}
% \end{macrocode}
% Handling the \emph{ypogegrammeni} output depends on the selected approach
@@ -1323,31 +1350,31 @@
% For clearing out trailing combining marks after we have dealt with
% the first one.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_upper_el_gobble:nnw
- #1#2#3 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_upper_el_gobble:nnnw
+ #1#2#3#4 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#3}
- { \@@_change_case_upper_el_gobble:nnN }
- { \@@_change_case_loop:nnw }
- {#1} {#2} #3 \q_@@_recursion_stop
+ \tl_if_head_is_N_type:nTF {#4}
+ { \@@_change_case_upper_el_gobble:nnnN }
+ { \@@_change_case_loop:nnnw }
+ {#1} {#2} {#3} #4 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_upper_el_gobble:nnN #1#2#3
+\cs_new:Npn \@@_change_case_upper_el_gobble:nnnN #1#2#3#4
{
- \token_if_cs:NTF #3
- { \@@_change_case_loop:nnw {#1} {#2} }
+ \token_if_cs:NTF #4
+ { \@@_change_case_loop:nnnw {#1} {#2} {#3} }
{
\@@_codepoint_process:nN
- { \@@_change_case_upper_el_gobble:nnn {#1} {#2} }
+ { \@@_change_case_upper_el_gobble:nnnn {#1} {#2} {#3} }
}
- #3
+ #4
}
-\cs_new:Npn \@@_change_case_upper_el_gobble:nnn #1#2#3
+\cs_new:Npn \@@_change_case_upper_el_gobble:nnnn #1#2#3#4
{
\bool_lazy_or:nnTF
- { \@@_change_case_if_greek_accent_p:n {#3} }
- { \@@_change_case_if_greek_breathing_p:n {#3} }
- { \@@_change_case_upper_el_gobble:nnw {#1} {#2} }
- { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ { \@@_change_case_if_greek_accent_p:n {#4} }
+ { \@@_change_case_if_greek_breathing_p:n {#4} }
+ { \@@_change_case_upper_el_gobble:nnnw {#1} {#2} {#3} }
+ { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 }
}
% \end{macrocode}
% Luckily the Greek range is limited and clear.
@@ -1597,98 +1624,101 @@
% \end{macro}
% \end{macro}
% \begin{macro}[EXP]
-% {\@@_change_case_boundary_upper_el:Nnnw, \@@_change_case_boundary_upper_el-x-iota:Nnnw}
-% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnN}
-% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnn}
-% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnw}
+% {
+% \@@_change_case_boundary_upper_el:Nnnnw,
+% \@@_change_case_boundary_upper_el-x-iota:Nnnnw
+% }
+% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnnw}
% There is one things that need special treatment at start start of
% words in Greek. For an isolated accent \emph{eta},
% which is handled by seeing if we have exactly one of the affected
% codepoints followed by a space or brace group.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_boundary_upper_el:Nnnw
- #1#2#3#4 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_boundary_upper_el:Nnnnw
+ #1#2#3#4#5 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_boundary_upper_el:nnN }
- { \@@_change_case_loop:nnw }
- {#2} {#3} #4 \q_@@_recursion_stop
+ \tl_if_head_is_N_type:nTF {#5}
+ { \@@_change_case_boundary_upper_el:nnnN }
+ { \@@_change_case_loop:nnnw }
+ {#2} {#3} {#4} #5 \q_@@_recursion_stop
}
-\cs_new_eq:cN { @@_change_case_boundary_upper_el-x-iota:Nnnw }
- \@@_change_case_boundary_upper_el:Nnnw
-\cs_new:Npn \@@_change_case_boundary_upper_el:nnN #1#2#3
+\cs_new_eq:cN { @@_change_case_boundary_upper_el-x-iota:Nnnnw }
+ \@@_change_case_boundary_upper_el:Nnnnw
+\cs_new:Npn \@@_change_case_boundary_upper_el:nnnN #1#2#3#4
{
- \token_if_cs:NTF #3
- { \@@_change_case_loop:nnw {#1} {#2} }
+ \token_if_cs:NTF #4
+ { \@@_change_case_loop:nnnw {#1} {#2} {#3} }
{
\@@_codepoint_process:nN
- { \@@_change_case_boundary_upper_el:nnn {#1} {#2} }
+ { \@@_change_case_boundary_upper_el:nnnn {#1} {#2} {#3} }
}
- #3
+ #4
}
-\cs_new:Npn \@@_change_case_boundary_upper_el:nnn #1#2#3
+\cs_new:Npn \@@_change_case_boundary_upper_el:nnnn #1#2#3#4
{
\bool_lazy_any:nTF
{
- { \@@_codepoint_compare_p:nNn {#3} = { "0389 } }
- { \@@_codepoint_compare_p:nNn {#3} = { "03AE } }
- { \@@_codepoint_compare_p:nNn {#3} = { "1F22 } }
- { \@@_codepoint_compare_p:nNn {#3} = { "1F2A } }
+ { \@@_codepoint_compare_p:nNn {#4} = { "0389 } }
+ { \@@_codepoint_compare_p:nNn {#4} = { "03AE } }
+ { \@@_codepoint_compare_p:nNn {#4} = { "1F22 } }
+ { \@@_codepoint_compare_p:nNn {#4} = { "1F2A } }
}
- { \@@_change_case_boundary_upper_el:nnnw {#1} {#2} {#3} }
- { \@@_change_case_breathing:nnn {#1} {#2} {#3} }
+ { \@@_change_case_boundary_upper_el:nnnnw {#1} {#2} {#3} {#4} }
+ { \@@_change_case_breathing:nnnn {#1} {#2} {#3} {#4} }
}
-\cs_new:Npn \@@_change_case_boundary_upper_el:nnnw
- #1#2#3#4 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_boundary_upper_el:nnnnw
+ #1#2#3#4#5 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ \tl_if_head_is_N_type:nTF {#5}
+ { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 }
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0389 }
- { \@@_change_case_catcode:nn {#3} { "0389 } }
+ { \@@_change_case_catcode:nn {#4} { "0389 } }
}
- \@@_change_case_loop:nnw {#1} {#2}
+ \@@_change_case_loop:nnnw {#1} {#2} {#3}
}
- #4 \q_@@_recursion_stop
+ #5 \q_@@_recursion_stop
}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
-% \begin{macro}[EXP]{\@@_change_case_breathing:nnn}
% \begin{macro}[EXP]{\@@_change_case_breathing:nnnn}
-% \begin{macro}[EXP]{\@@_change_case_breathing:nnnnw}
+% \begin{macro}[EXP]{\@@_change_case_breathing:nnnnn}
% \begin{macro}[EXP]{\@@_change_case_breathing:nnnnnw}
-% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnnn}
-% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnw}
-% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnN}
-% \begin{macro}[EXP]{\@@_change_case_breathing_dialytika:nnn}
+% \begin{macro}[EXP]{\@@_change_case_breathing:nnnnnnw}
+% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnnnn}
+% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnnw}
+% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_breathing_dialytika:nnnn}
% In Greek, breathing diacritics are normally dropped when uppercasing:
% see the code for the general case. However, for the first character
% of a word, if there is a breather \emph{and} the next character takes
% a \emph{dialytika}, it needs to be added. We start by checking if
% the current codepoint is in the Greek range, then decomposing.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_breathing:nnn #1#2#3
+\cs_new:Npn \@@_change_case_breathing:nnnn #1#2#3#4
{
- \@@_change_case_if_greek:nTF {#3}
+ \@@_change_case_if_greek:nTF {#4}
{
- \exp_args:Ne \@@_change_case_breathing:nnnn
+ \exp_args:Ne \@@_change_case_breathing:nnnnn
{
\codepoint_to_nfd:n
- { \@@_codepoint_from_chars:Nw #3 }
+ { \@@_codepoint_from_chars:Nw #4 }
}
- {#1} {#2} {#3}
+ {#1} {#2} {#3} {#4}
}
- { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 }
}
-\cs_new:Npn \@@_change_case_breathing:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_breathing:nnnnn #1#2#3#4#5
{
\@@_codepoint_process:nN
- { \@@_change_case_breathing:nnnnw {#2} {#3} {#4} }
+ { \@@_change_case_breathing:nnnnnw {#2} {#3} {#4} {#5} }
#1 \q_mark
}
% \end{macrocode}
@@ -1699,36 +1729,36 @@
% and second if the final resulting codepoint is one of the two we
% care about.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_breathing:nnnnw #1#2#3#4#5 \q_mark
+\cs_new:Npn \@@_change_case_breathing:nnnnnw #1#2#3#4#5#6 \q_mark
{
- \tl_if_blank:nTF {#5}
- { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ \tl_if_blank:nTF {#6}
+ { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 }
{
\@@_codepoint_process:nN
- { \@@_change_case_breathing:nnnnnw {#1} {#2} {#3} {#4} }
- #5 \q_mark
+ { \@@_change_case_breathing:nnnnnnw {#1} {#2} {#3} {#4} {#5} }
+ #6 \q_mark
}
}
-\cs_new:Npn \@@_change_case_breathing:nnnnnw #1#2#3#4#5#6 \q_mark
+\cs_new:Npn \@@_change_case_breathing:nnnnnnw #1#2#3#4#5#6#7 \q_mark
{
- \tl_if_blank:nTF {#6}
+ \tl_if_blank:nTF {#7}
{
- \@@_change_case_breathing_aux:nnnnn
- {#1} {#2} {#3} {#4} {#5}
+ \@@_change_case_breathing_aux:nnnnnn
+ {#1} {#2} {#3} {#4} {#5} {#6}
}
{
\@@_codepoint_process:nN
- { \@@_change_case_breathing:nnnnnw {#1} {#2} {#3} {#4} }
- #6 \q_mark
+ { \@@_change_case_breathing:nnnnnnw {#1} {#2} {#3} {#4} {#5} }
+ #7 \q_mark
}
}
-\cs_new:Npn \@@_change_case_breathing_aux:nnnnn #1#2#3#4#5
+\cs_new:Npn \@@_change_case_breathing_aux:nnnnnn #1#2#3#4#5#6
{
\bool_lazy_or:nnTF
- { \@@_codepoint_compare_p:nNn {#5} = { "0313 } }
- { \@@_codepoint_compare_p:nNn {#5} = { "0314 } }
- { \@@_change_case_breathing_aux:nnnw {#1} {#2} {#4} }
- { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ { \@@_codepoint_compare_p:nNn {#6} = { "0313 } }
+ { \@@_codepoint_compare_p:nNn {#6} = { "0314 } }
+ { \@@_change_case_breathing_aux:nnnnw {#1} {#2} {#3} {#5} }
+ { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 }
}
% \end{macrocode}
% Now the lookahead can be fired: check the next codepoint and assess
@@ -1736,29 +1766,29 @@
% breathing mark or generate the \emph{dialytika}: the
% latter is code shared with the general mechanism.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_breathing_aux:nnnw #1#2#3#4
+\cs_new:Npn \@@_change_case_breathing_aux:nnnnw #1#2#3#4#5
\q_@@_recursion_stop
{
\@@_change_case_store:e
- { \@@_change_case_codepoint:nn { upper } {#3} }
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_breathing_aux:nnN }
- { \@@_change_case_loop:nnw }
- {#1} {#2} #4 \q_@@_recursion_stop
+ { \@@_change_case_codepoint:nn { upper } {#4} }
+ \tl_if_head_is_N_type:nTF {#5}
+ { \@@_change_case_breathing_aux:nnnN }
+ { \@@_change_case_loop:nnnw }
+ {#1} {#2} {#3} #5 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_breathing_aux:nnN #1#2#3
+\cs_new:Npn \@@_change_case_breathing_aux:nnnN #1#2#3#4
{
\@@_codepoint_process:nN
- { \@@_change_case_breathing_dialytika:nnn {#1} {#2} } #3
+ { \@@_change_case_breathing_dialytika:nnnn {#1} {#2} {#3} } #4
}
-\cs_new:Npn \@@_change_case_breathing_dialytika:nnn #1#2#3
+\cs_new:Npn \@@_change_case_breathing_dialytika:nnnn #1#2#3#4
{
- \@@_change_case_if_takes_dialytika:nTF {#3}
+ \@@_change_case_if_takes_dialytika:nTF {#4}
{
- \@@_change_case_upper_el_dialytika:n {#3}
- \@@_change_case_loop:nnw {#1} {#2}
+ \@@_change_case_upper_el_dialytika:n {#4}
+ \@@_change_case_loop:nnnw {#1} {#2} {#3}
}
- { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ { \@@_change_case_loop:nnnw {#1} {#2} {#3} #4 }
}
% \end{macrocode}
% \end{macro}
@@ -1769,88 +1799,88 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \begin{macro}[EXP]{\@@_change_case_title_el:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_title_el:nnnnn}
% Titlecasing retains accents, but to prevent the uppercasing code
% from kicking in, there has to be an explicit function here.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_title_el:nnnn #1#2#3#4
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+\cs_new:Npn \@@_change_case_title_el:nnnnn #1#2#3#4#5
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]
% {
-% \@@_change_case_upper_hy:nnnn ,
-% \@@_change_case_title_hy:nnnn ,
-% \@@_change_case_upper_hy-x-yiwn:nnnn ,
-% \@@_change_case_title_hy-x-yiwn:nnnn
+% \@@_change_case_upper_hy:nnnnn ,
+% \@@_change_case_title_hy:nnnnn ,
+% \@@_change_case_upper_hy-x-yiwn:nnnnn ,
+% \@@_change_case_title_hy-x-yiwn:nnnnn
% }
% See \url{https://www.unicode.org/L2/L2020/20143-armenian-ech-yiwn.pdf}.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_upper_hy:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_hy:nnnnn #1#2#3#4#5
{
- \@@_codepoint_compare:nNnTF {#4} = { "0587 }
+ \@@_codepoint_compare:nNnTF {#5} = { "0587 }
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0535 }
- { \@@_change_case_catcode:nn {#4} { "0535 } }
+ { \@@_change_case_catcode:nn {#5} { "0535 } }
\codepoint_generate:nn { "054E }
- { \@@_change_case_catcode:nn {#4} { "054E } }
+ { \@@_change_case_catcode:nn {#5} { "054E } }
}
- \use:c { @@_change_case_next_ #2 :nn }
- {#2} {#3}
+ \use:c { @@_change_case_next_ #2 :nnn }
+ {#2} {#3} {#4}
}
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
}
-\cs_new:Npn \@@_change_case_title_hy:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_title_hy:nnnnn #1#2#3#4#5
{
- \@@_codepoint_compare:nNnTF {#4} = { "0587 }
+ \@@_codepoint_compare:nNnTF {#5} = { "0587 }
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0535 }
- { \@@_change_case_catcode:nn {#4} { "0535 } }
+ { \@@_change_case_catcode:nn {#5} { "0535 } }
\codepoint_generate:nn { "057E }
- { \@@_change_case_catcode:nn {#4} { "057E } }
+ { \@@_change_case_catcode:nn {#5} { "057E } }
}
- \use:c { @@_change_case_next_ #2 :nn }
- {#2} {#3}
+ \use:c { @@_change_case_next_ #2 :nnn }
+ {#2} {#3} {#4}
}
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
}
-\cs_new:cpn { @@_change_case_upper_hy-x-yiwn:nnnn } #1#2#3#4
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
-\cs_new_eq:cc { @@_change_case_title_hy-x-yiwn:nnnn }
- { @@_change_case_upper_hy-x-yiwn:nnnn }
+\cs_new:cpn { @@_change_case_upper_hy-x-yiwn:nnnnn } #1#2#3#4#5
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
+\cs_new_eq:cc { @@_change_case_title_hy-x-yiwn:nnnnn }
+ { @@_change_case_upper_hy-x-yiwn:nnnnn }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_change_case_lower_la-x-medieval:nnnn}
-% \begin{macro}[EXP]{\@@_change_case_upper_la-x-medieval:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_lower_la-x-medieval:nnnnn}
+% \begin{macro}[EXP]{\@@_change_case_upper_la-x-medieval:nnnnn}
% Simply swaps of characters.
% \begin{macrocode}
-\cs_new:cpn { @@_change_case_lower_la-x-medieval:nnnn } #1#2#3#4
+\cs_new:cpn { @@_change_case_lower_la-x-medieval:nnnnn } #1#2#3#4#5
{
- \@@_codepoint_compare:nNnTF {#4} = { "0056 }
+ \@@_codepoint_compare:nNnTF {#5} = { "0056 }
{
\@@_change_case_store:e
- { \char_generate:nn { "0075 } { \@@_char_catcode:N #4 } }
- \use:c { @@_change_case_next_ #2 :nn }
- {#2} {#3}
+ { \char_generate:nn { "0075 } { \@@_char_catcode:N #5 } }
+ \use:c { @@_change_case_next_ #2 :nnn }
+ {#2} {#3} {#4}
}
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
}
-\cs_new:cpn { @@_change_case_upper_la-x-medieval:nnnn } #1#2#3#4
+\cs_new:cpn { @@_change_case_upper_la-x-medieval:nnnnn } #1#2#3#4#5
{
- \@@_codepoint_compare:nNnTF {#4} = { "0075 }
+ \@@_codepoint_compare:nNnTF {#5} = { "0075 }
{
\@@_change_case_store:e
- { \char_generate:nn { "0056 } { \@@_char_catcode:N #4 } }
- \use:c { @@_change_case_next_ #2 :nn }
- {#2} {#3}
+ { \char_generate:nn { "0056 } { \@@_char_catcode:N #5 } }
+ \use:c { @@_change_case_next_ #2 :nnn }
+ {#2} {#3} {#4}
}
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
}
% \end{macrocode}
% \end{macro}
@@ -1858,62 +1888,62 @@
%
% \begin{macro}[EXP]
% {
-% \@@_change_cases_lower_lt:nnnn ,
-% \@@_change_cases_lower_lt_auxi:nnnn ,
-% \@@_change_cases_lower_lt_auxii:nnnn
+% \@@_change_cases_lower_lt:nnnnn ,
+% \@@_change_cases_lower_lt_auxi:nnnnn ,
+% \@@_change_cases_lower_lt_auxii:nnnnn
% }
-% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnw}
-% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnN}
-% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnn}
+% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnnw}
+% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnnN}
+% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnnn}
% For Lithuanian, the issue to be dealt with is dots over lower case
% letters: these should be present if there is another accent. The first step
% is a simple match attempt: look for the three uppercase accented letters
% which should gain a dot-above char in their lowercase form.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_lower_lt:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_lower_lt:nnnnn #1#2#3#4#5
{
- \exp_args:Ne \@@_change_case_lower_lt_auxi:nnnn
+ \exp_args:Ne \@@_change_case_lower_lt_auxi:nnnnn
{
- \int_case:nn { \@@_codepoint_from_chars:Nw #4 }
+ \int_case:nn { \@@_codepoint_from_chars:Nw #5 }
{
{ "00CC } { "0300 }
{ "00CD } { "0301 }
{ "0128 } { "0303 }
}
}
- {#2} {#3} {#4}
+ {#2} {#3} {#4} {#5}
}
% \end{macrocode}
% If there was a hit, output the result with the dot-above and move on.
% Otherwise, look for one of the three letters that can take a combining
% accent: I, J nd I-ogonek.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_lower_lt_auxi:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_lower_lt_auxi:nnnnn #1#2#3#4#5
{
\tl_if_blank:nTF {#1}
{
- \exp_args:Ne \@@_change_case_lower_lt_auxii:nnnn
+ \exp_args:Ne \@@_change_case_lower_lt_auxii:nnnnn
{
- \int_case:nn { \@@_codepoint_from_chars:Nw #4 }
+ \int_case:nn { \@@_codepoint_from_chars:Nw #5 }
{
{ "0049 } { "0069 }
{ "004A } { "006A }
{ "012E } { "012F }
}
}
- {#2} {#3} {#4}
+ {#2} {#3} {#4} {#5}
}
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0069 }
- { \@@_change_case_catcode:nn {#4} { "0069 } }
+ { \@@_change_case_catcode:nn {#5} { "0069 } }
\codepoint_generate:nn { "0307 }
- { \@@_change_case_catcode:nn {#4} { "0307 } }
+ { \@@_change_case_catcode:nn {#5} { "0307 } }
\codepoint_generate:nn {#1}
- { \@@_change_case_catcode:nn {#4} {#1} }
+ { \@@_change_case_catcode:nn {#5} {#1} }
}
- \@@_change_case_loop:nnw {#2} {#3}
+ \@@_change_case_loop:nnnw {#2} {#3} {#4}
}
}
% \end{macrocode}
@@ -1921,55 +1951,55 @@
% then need to look for a combining accent: as usual, we need to be aware of
% the loop situation.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_lower_lt_auxii:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_lower_lt_auxii:nnnnn #1#2#3#4#5
{
\tl_if_blank:nTF {#1}
- { \@@_change_case_codepoint:nnnn {#2} {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn {#2} {#2} {#3} {#4} {#5} }
{
\@@_change_case_store:e
{
\codepoint_generate:nn {#1}
- { \@@_change_case_catcode:nn {#4} {#1} }
+ { \@@_change_case_catcode:nn {#5} {#1} }
}
- \@@_change_case_lower_lt:nnw {#2} {#3}
+ \@@_change_case_lower_lt:nnnw {#2} {#3} {#4}
}
}
-\cs_new:Npn \@@_change_case_lower_lt:nnw #1#2#3 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_lower_lt:nnnw #1#2#3#4 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#3}
- { \@@_change_case_lower_lt:nnN }
- { \@@_change_case_loop:nnw }
- {#1} {#2} #3 \q_@@_recursion_stop
+ \tl_if_head_is_N_type:nTF {#4}
+ { \@@_change_case_lower_lt:nnnN }
+ { \@@_change_case_loop:nnnw }
+ {#1} {#2} {#3} #4 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_lower_lt:nnN #1#2#3
+\cs_new:Npn \@@_change_case_lower_lt:nnnN #1#2#3#4
{
\@@_codepoint_process:nN
- { \@@_change_case_lower_lt:nnn {#1} {#2} } #3
+ { \@@_change_case_lower_lt:nnnn {#1} {#2} {#3} } #4
}
-\cs_new:Npn \@@_change_case_lower_lt:nnn #1#2#3
+\cs_new:Npn \@@_change_case_lower_lt:nnnn #1#2#3#4
{
\bool_lazy_and:nnT
{
\bool_lazy_or_p:nn
- { ! \tl_if_single_p:n {#3} }
- { ! \token_if_cs_p:N #3 }
+ { ! \tl_if_single_p:n {#4} }
+ { ! \token_if_cs_p:N #4 }
}
{
\bool_lazy_any_p:n
{
- { \@@_codepoint_compare_p:nNn {#3} = { "0300 } }
- { \@@_codepoint_compare_p:nNn {#3} = { "0301 } }
- { \@@_codepoint_compare_p:nNn {#3} = { "0303 } }
+ { \@@_codepoint_compare_p:nNn {#4} = { "0300 } }
+ { \@@_codepoint_compare_p:nNn {#4} = { "0301 } }
+ { \@@_codepoint_compare_p:nNn {#4} = { "0303 } }
}
}
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0307 }
- { \@@_change_case_catcode:nn {#3} { "0307 } }
+ { \@@_change_case_catcode:nn {#4} { "0307 } }
}
}
- \@@_change_case_loop:nnw {#1} {#2} #3
+ \@@_change_case_loop:nnnw {#1} {#2} {#3} #4
}
% \end{macrocode}
% \end{macro}
@@ -1978,64 +2008,64 @@
% \end{macro}
% \begin{macro}[EXP]
% {
-% \@@_change_cases_upper_lt:nnnn ,
-% \@@_change_cases_upper_lt_aux:nnnn
+% \@@_change_cases_upper_lt:nnnnn ,
+% \@@_change_cases_upper_lt_aux:nnnnn
% }
-% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnw}
-% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnN}
-% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnn}
+% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnnw}
+% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnnN}
+% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnnn}
% The uppercasing version: first find i/j/i-ogonek, then look for the
% combining char: drop it if present.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_upper_lt:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_lt:nnnnn #1#2#3#4#5
{
- \exp_args:Ne \@@_change_case_upper_lt_aux:nnnn
+ \exp_args:Ne \@@_change_case_upper_lt_aux:nnnnn
{
- \int_case:nn { \@@_codepoint_from_chars:Nw #4 }
+ \int_case:nn { \@@_codepoint_from_chars:Nw #5 }
{
{ "0069 } { "0049 }
{ "006A } { "004A }
{ "012F } { "012E }
}
}
- {#2} {#3} {#4}
+ {#2} {#3} {#4} {#5}
}
-\cs_new:Npn \@@_change_case_upper_lt_aux:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_lt_aux:nnnnn #1#2#3#4#5
{
\tl_if_blank:nTF {#1}
- { \@@_change_case_codepoint:nnnn { upper } {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn { upper } {#2} {#3} {#4} {#5} }
{
\@@_change_case_store:e
{
\codepoint_generate:nn {#1}
- { \@@_change_case_catcode:nn {#4} {#1} }
+ { \@@_change_case_catcode:nn {#5} {#1} }
}
- \@@_change_case_upper_lt:nnw {#2} {#3}
+ \@@_change_case_upper_lt:nnnw {#2} {#3} {#4}
}
}
-\cs_new:Npn \@@_change_case_upper_lt:nnw #1#2#3 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_upper_lt:nnnw #1#2#3#4 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#3}
- { \@@_change_case_upper_lt:nnN }
- { \use:c { @@_change_case_next_ #1 :nn } }
- {#1} {#2} #3 \q_@@_recursion_stop
+ \tl_if_head_is_N_type:nTF {#4}
+ { \@@_change_case_upper_lt:nnnN }
+ { \use:c { @@_change_case_next_ #1 :nnn } }
+ {#1} {#2} {#3} #4 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_upper_lt:nnN #1#2#3
+\cs_new:Npn \@@_change_case_upper_lt:nnnN #1#2#3#4
{
\@@_codepoint_process:nN
- { \@@_change_case_upper_lt:nnn {#1} {#2} } #3
+ { \@@_change_case_upper_lt:nnnn {#1} {#2} {#3} } #4
}
-\cs_new:Npn \@@_change_case_upper_lt:nnn #1#2#3
+\cs_new:Npn \@@_change_case_upper_lt:nnnn #1#2#3#4
{
\bool_lazy_and:nnTF
{
\bool_lazy_or_p:nn
- { ! \tl_if_single_p:n {#3} }
- { ! \token_if_cs_p:N #3 }
+ { ! \tl_if_single_p:n {#4} }
+ { ! \token_if_cs_p:N #4 }
}
- { \@@_codepoint_compare_p:nNn {#3} = { "0307 } }
- { \use:c { @@_change_case_next_ #1 :nn } {#1} {#2} }
- { \use:c { @@_change_case_next_ #1 :nn } {#1} {#2} #3 }
+ { \@@_codepoint_compare_p:nNn {#4} = { "0307 } }
+ { \use:c { @@_change_case_next_ #1 :nnn } {#1} {#2} {#3} }
+ { \use:c { @@_change_case_next_ #1 :nnn } {#1} {#2} {#3} #4 }
}
% \end{macrocode}
% \end{macro}
@@ -2044,84 +2074,84 @@
% \end{macro}
%
% \begin{macro}[EXP]
-% {\@@_change_case_title_nl:nnnn, \@@_change_case_title_nl_aux:nnnn}
-% \begin{macro}[EXP]{\@@_change_case_title_nl:nnw}
-% \begin{macro}[EXP]{\@@_change_case_title_nl:nnN}
+% {\@@_change_case_title_nl:nnnnn, \@@_change_case_title_nl_aux:nnnnn}
+% \begin{macro}[EXP]{\@@_change_case_title_nl:nnnw}
+% \begin{macro}[EXP]{\@@_change_case_title_nl:nnnN}
% For Dutch, there is a single look-ahead test for \texttt{ij} when
% title casing. If the appropriate letters are found, produce \texttt{IJ}
% and gobble the \texttt{j}/\texttt{J}.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_title_nl:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_title_nl:nnnnn #1#2#3#4#5
{
- \tl_if_single:nTF {#4}
- { \@@_change_case_title_nl_aux:nnnn }
- { \@@_change_case_codepoint:nnnn }
- {#1} {#2} {#3} {#4}
+ \tl_if_single:nTF {#5}
+ { \@@_change_case_title_nl_aux:nnnnn }
+ { \@@_change_case_codepoint:nnnnn }
+ {#1} {#2} {#3} {#4} {#5}
}
-\cs_new:Npn \@@_change_case_title_nl_aux:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_title_nl_aux:nnnnn #1#2#3#4#5
{
\bool_lazy_or:nnTF
- { \int_compare_p:nNn {`#4} = { "0049 } }
- { \int_compare_p:nNn {`#4} = { "0069 } }
+ { \int_compare_p:nNn {`#5} = { "0049 } }
+ { \int_compare_p:nNn {`#5} = { "0069 } }
{
\@@_change_case_store:e
- { \char_generate:nn { "0049 } { \@@_char_catcode:N #4 } }
- \@@_change_case_title_nl:nnw {#2} {#3}
+ { \char_generate:nn { "0049 } { \@@_char_catcode:N #5 } }
+ \@@_change_case_title_nl:nnnw {#2} {#3} {#4}
}
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
}
-\cs_new:Npn \@@_change_case_title_nl:nnw #1#2#3 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_title_nl:nnnw #1#2#3#4 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#3}
- { \@@_change_case_title_nl:nnN }
- { \use:c { @@_change_case_next_ #1 :nn } }
- {#1} {#2} #3 \q_@@_recursion_stop
+ \tl_if_head_is_N_type:nTF {#4}
+ { \@@_change_case_title_nl:nnnN }
+ { \use:c { @@_change_case_next_ #1 :nnn } }
+ {#1} {#2} {#3} #4 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_title_nl:nnN #1#2#3
+\cs_new:Npn \@@_change_case_title_nl:nnnN #1#2#3#4
{
\bool_lazy_and:nnTF
- { ! \token_if_cs_p:N #3 }
+ { ! \token_if_cs_p:N #4 }
{
\bool_lazy_or_p:nn
- { \int_compare_p:nNn {`#3} = { "004A } }
- { \int_compare_p:nNn {`#3} = { "006A } }
+ { \int_compare_p:nNn {`#4} = { "004A } }
+ { \int_compare_p:nNn {`#4} = { "006A } }
}
{
\@@_change_case_store:e
- { \char_generate:nn { "004A } { \@@_char_catcode:N #3 } }
- \use:c { @@_change_case_next_ #1 :nn } {#1} {#2}
+ { \char_generate:nn { "004A } { \@@_char_catcode:N #4 } }
+ \use:c { @@_change_case_next_ #1 :nnn } {#1} {#2} {#3}
}
- { \use:c { @@_change_case_next_ #1 :nn } {#1} {#2} #3 }
+ { \use:c { @@_change_case_next_ #1 :nnn } {#1} {#2} {#3} #4 }
}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnnn}
-% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnNw}
-% \begin{macro}[EXP]{\@@_change_case_lower_tr:NnnN}
-% \begin{macro}[EXP]{\@@_change_case_lower_tr:Nnnn}
+% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnnnn}
+% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnnNw}
+% \begin{macro}[EXP]{\@@_change_case_lower_tr:NnnnN}
+% \begin{macro}[EXP]{\@@_change_case_lower_tr:Nnnnn}
% The Turkic languages need special treatment for dotted-i and dotless-i.
% The lower casing rule can be expressed in terms of searching first for
% either a dotless-I or a dotted-I. In the latter case the mapping is
% easy, but in the former there is a second stage search.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_lower_tr:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_lower_tr:nnnnn #1#2#3#4#5
{
- \@@_codepoint_compare:nNnTF {#4} = { "0049 }
- { \@@_change_case_lower_tr:nnNw {#1} {#3} #4 }
+ \@@_codepoint_compare:nNnTF {#5} = { "0049 }
+ { \@@_change_case_lower_tr:nnnNw {#1} {#3} {#4} #5 }
{
- \@@_codepoint_compare:nNnTF {#4} = { "0130 }
+ \@@_codepoint_compare:nNnTF {#5} = { "0130 }
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0069 }
- { \@@_change_case_catcode:nn {#4} { "0069 } }
+ { \@@_change_case_catcode:nn {#5} { "0069 } }
}
- \@@_change_case_loop:nnw {#1} {#3}
+ \@@_change_case_loop:nnnw {#1} {#3} {#4}
}
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
}
}
% \end{macrocode}
@@ -2130,41 +2160,41 @@
% combination is found both the dotless-I and the dot-above char have to
% be removed from the input.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_lower_tr:nnNw #1#2#3#4 \q_@@_recursion_stop
+\cs_new:Npn \@@_change_case_lower_tr:nnnNw #1#2#3#4#5 \q_@@_recursion_stop
{
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_lower_tr:NnnN #3 {#1} {#2} }
+ \tl_if_head_is_N_type:nTF {#5}
+ { \@@_change_case_lower_tr:NnnnN #4 {#1} {#2} {#3} }
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0131 }
- { \@@_change_case_catcode:nn {#3} { "0131 } }
+ { \@@_change_case_catcode:nn {#4} { "0131 } }
}
- \@@_change_case_loop:nnw {#1} {#2}
+ \@@_change_case_loop:nnnw {#1} {#2} {#3}
}
- #4 \q_@@_recursion_stop
+ #5 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_lower_tr:NnnN #1#2#3#4
+\cs_new:Npn \@@_change_case_lower_tr:NnnnN #1#2#3#4#5
{
\@@_codepoint_process:nN
- { \@@_change_case_lower_tr:Nnnn #1 {#2} {#3} } #4
+ { \@@_change_case_lower_tr:Nnnnn #1 {#2} {#3} {#4} } #5
}
-\cs_new:Npn \@@_change_case_lower_tr:Nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_lower_tr:Nnnnn #1#2#3#4#5
{
\bool_lazy_or:nnTF
{
\bool_lazy_and_p:nn
- { \tl_if_single_p:n {#4} }
- { \token_if_cs_p:N #4 }
+ { \tl_if_single_p:n {#5} }
+ { \token_if_cs_p:N #5 }
}
- { ! \@@_codepoint_compare_p:nNn {#4} = { "0307 } }
+ { ! \@@_codepoint_compare_p:nNn {#5} = { "0307 } }
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0131 }
{ \@@_change_case_catcode:nn {#1} { "0131 } }
}
- \@@_change_case_loop:nnw {#2} {#3} #4
+ \@@_change_case_loop:nnnw {#2} {#3} {#4} #5
}
{
\@@_change_case_store:e
@@ -2172,7 +2202,7 @@
\codepoint_generate:nn { "0069 }
{ \@@_change_case_catcode:nn {#1} { "0069 } }
}
- \@@_change_case_loop:nnw {#2} {#3}
+ \@@_change_case_loop:nnnw {#2} {#3} {#4}
}
}
% \end{macrocode}
@@ -2180,33 +2210,33 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \begin{macro}[EXP]{\@@_change_case_upper_tr:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_upper_tr:nnnnn}
% Uppercasing is easier: just one exception with no context.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_upper_tr:nnnn #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_tr:nnnnn #1#2#3#4#5
{
- \@@_codepoint_compare:nNnTF {#4} = { "0069 }
+ \@@_codepoint_compare:nNnTF {#5} = { "0069 }
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0130 }
- { \@@_change_case_catcode:nn {#4} { "0130 } }
+ { \@@_change_case_catcode:nn {#5} { "0130 } }
}
- \use:c { @@_change_case_next_ #2 :nn } {#2} {#3}
+ \use:c { @@_change_case_next_ #2 :nnn } {#2} {#3} {#4}
}
- { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+ { \@@_change_case_codepoint:nnnnn {#1} {#2} {#3} {#4} {#5} }
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]
-% {\@@_change_case_lower_az:nnnn, \@@_change_case_upper_az:nnnn}
+% {\@@_change_case_lower_az:nnnnn, \@@_change_case_upper_az:nnnnn}
% Straight copies.
% \begin{macrocode}
-\cs_new_eq:NN \@@_change_case_lower_az:nnnn
- \@@_change_case_lower_tr:nnnn
-\cs_new_eq:NN \@@_change_case_upper_az:nnnn
- \@@_change_case_upper_tr:nnnn
+\cs_new_eq:NN \@@_change_case_lower_az:nnnnn
+ \@@_change_case_lower_tr:nnnnn
+\cs_new_eq:NN \@@_change_case_upper_az:nnnnn
+ \@@_change_case_upper_tr:nnnnn
% \end{macrocode}
% \end{macro}
%
diff --git a/macros/latex/contrib/l3kernel/l3text-map.dtx b/macros/latex/contrib/l3kernel/l3text-map.dtx
index 8b3ac6098c..d863e51ace 100644
--- a/macros/latex/contrib/l3kernel/l3text-map.dtx
+++ b/macros/latex/contrib/l3kernel/l3text-map.dtx
@@ -2,7 +2,7 @@
%
%% File: l3text-map.dtx
%
-% Copyright (C) 2022,2023 The LaTeX Project
+% Copyright (C) 2022-2023 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
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3text-purify.dtx b/macros/latex/contrib/l3kernel/l3text-purify.dtx
index 075b370737..5770853cd7 100644
--- a/macros/latex/contrib/l3kernel/l3text-purify.dtx
+++ b/macros/latex/contrib/l3kernel/l3text-purify.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3text.dtx b/macros/latex/contrib/l3kernel/l3text.dtx
index 8df534cc84..ea33b58855 100644
--- a/macros/latex/contrib/l3kernel/l3text.dtx
+++ b/macros/latex/contrib/l3kernel/l3text.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -94,18 +94,18 @@
%
% \section{Case changing}
%
-% \begin{function}[EXP, added = 2019-11-20, updated = 2022-10-13]
+% \begin{function}[EXP, added = 2019-11-20, updated = 2023-07-08]
% {
-% \text_lowercase:n, \text_uppercase:n, \text_titlecase:n,
+% \text_lowercase:n, \text_uppercase:n, \text_titlecase_all:n,
% \text_titlecase_first:n,
-% \text_lowercase:nn, \text_uppercase:nn, \text_titlecase:nn,
+% \text_lowercase:nn, \text_uppercase:nn, \text_titlecase_all:nn,
% \text_titlecase_first:nn
% }
% \begin{syntax}
% \cs{text_uppercase:n} \Arg{tokens}
% \cs{text_uppercase:nn} \Arg{BCP-47} \Arg{tokens}
% \end{syntax}
-% Takes user input \meta{text} first applies \cs{text_expand}, then
+% Takes user input \meta{text} first applies \cs{text_expand:n}, then
% transforms the case of character tokens as specified by the
% function name. The category code of letters are not changed by this
% process when Unicode engines are used; in $8$-bit engines, case changed
@@ -115,11 +115,13 @@
%
% Upper- and lowercase have the obvious meanings. Titlecasing may be regarded
% informally as converting the first character of the \meta{tokens} to
-% uppercase and the rest to lowercase. However, the process is more complex
+% uppercase. However, the process is more complex
% than this as there are some situations where a single lowercase character
% maps to a special form, for example \texttt{ij} in Dutch which becomes
-% \texttt{IJ}. The \texttt{titlecase_first} variant does not attempt
-% any case changing at all after the first letter has been processed.
+% \texttt{IJ}. There are two functions available for titlecasing: one which
+% applies the change to each \enquote{word} and a second which only applies
+% at the start of the input. (Here, \enquote{word} boundaries are spaces:
+% at present, full Unicode word breaking is not attempted.)
%
% Importantly, notice that these functions are intended for working with
% user \emph{text for typesetting}. For case changing programmatic data see
@@ -163,10 +165,7 @@
% I-dot and introduced when upper casing i-dotless.
% \item German (\texttt{de-x-eszett}).
% An alternative mapping for German in which the lowercase
-% \emph{Eszett} maps to a \emph{gro\ss{}es Eszett}. Since there is
-% a |T1| slot for the \emph{gro\ss{}es Eszett} in |T1|, this
-% tailoring \emph{is} available with \pdfTeX{} as well as in the
-% Unicode \TeX{} engines.
+% \emph{Eszett} maps to a \emph{gro\ss{}es Eszett}.
% \item Greek (\texttt{el}).
% Removes accents from Greek letters when uppercasing; titlecasing
% leaves accents in place. A variant \texttt{el-x-iota} is available
@@ -185,25 +184,17 @@
% 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
-% retains two separate letters, thus this transformation \emph{is}
-% available using \pdfTeX{}.
+% input produces \texttt{IJ} rather than \texttt{Ij}.
% \end{itemize}
%
-% For titlecasing, note that there are two functions available. The
-% function \cs{text_titlecase:n} applies (broadly) uppercasing to the first
-% letter of the input, then lowercasing to the remainder. In contrast,
-% \cs{text_titlecase_first:n} \emph{only} carries out the uppercasing operation,
-% and leaves the balance of the input unchanged. Determining whether
-% non-letter characters at the start of text should switch from upper- to
-% lowercasing is controllable. When \cs{l_text_titlecase_check_letter_bool} is
+% Determining whether non-letter characters at the start of text should count
+% as the uppercase element is controllable. When \cs{l_text_titlecase_check_letter_bool} is
% \texttt{true}, characters which are not letters (category code~$11$) are
-% left unchanged and \enquote{skipped}: the first \emph{letter} is uppercased.
+% \enquote{skipped}: the first \emph{letter} is uppercased.
% (With $8$-bit engines, this is extended to active characters which form
% part of a multi-byte letter codepoint.) When
% \cs{l_text_titlecase_check_letter_bool} is \texttt{false}, the first
-% character is uppercased, and the rest lowercased, irrespective of the nature
-% of the character.
+% character is uppercased, irrespective of the category code of the character.
%
% \begin{function}[added = 2022-07-04]
% {
diff --git a/macros/latex/contrib/l3kernel/l3tl-analysis.dtx b/macros/latex/contrib/l3kernel/l3tl-analysis.dtx
index 9cadf04e87..6336b0d076 100644
--- a/macros/latex/contrib/l3kernel/l3tl-analysis.dtx
+++ b/macros/latex/contrib/l3kernel/l3tl-analysis.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -177,9 +177,6 @@
% by avoiding \cs{exp_not:n} for characters other than active and macro
% parameters.)
%
-% ^^A todo: ask LuaTeX list for an \ifx\undefined <active char>
-% ^^A which does not add the <active char> in memory.
-%
% \begin{macrocode}
%<*package>
% \end{macrocode}
@@ -443,6 +440,42 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\@@_analysis_disable_char:N}
+% Similar to \cs{@@_analysis_disable:n}, but it receives a normal
+% character token, tests if that token is active (by turning it into
+% a space: the active space has been undefined at this point), and
+% if so, disables it. Even if the character is active and set equal
+% to a primitive conditional, nothing blows up.
+% Again, in \pTeX{} and \upTeX{} we skip characters beyond $[0,255]$,
+% which cannot be active anyways.
+% \begin{macrocode}
+\group_begin:
+ \char_set_catcode_active:N \^^@
+ \cs_new_protected:Npn \@@_analysis_disable_char:N #1
+ {
+ \tex_lccode:D `#1 = 32 \exp_stop_f:
+ \tex_lowercase:D { \if_meaning:w #1 } \tex_undefined:D
+ \tex_let:D #1 \tex_undefined:D
+ \fi:
+ }
+ \bool_lazy_or:nnT
+ { \sys_if_engine_ptex_p: }
+ { \sys_if_engine_uptex_p: }
+ {
+ \cs_gset_protected:Npn \@@_analysis_disable_char:N #1
+ {
+ \if_int_compare:w 256 > `#1 \exp_stop_f:
+ \tex_lccode:D `#1 = 32 \exp_stop_f:
+ \tex_lowercase:D { \if_meaning:w #1 } \tex_undefined:D
+ \tex_let:D #1 \tex_undefined:D
+ \fi:
+ \fi:
+ }
+ }
+\group_end:
+% \end{macrocode}
+% \end{macro}
+%
% \subsection{First pass}
%
% The goal of this pass is to detect special (non-\texttt{N}-type) tokens,
@@ -737,7 +770,7 @@
\exp_after:wN \use_ii:nn
\fi:
{
- \@@_analysis_disable:n { `#1 }
+ \@@_analysis_disable_char:N #1
\int_incr:N \l_@@_analysis_normal_int
}
{ \@@_analysis_cs_space_count:NN \@@_analysis_a_cs:ww #1 }
diff --git a/macros/latex/contrib/l3kernel/l3tl.dtx b/macros/latex/contrib/l3kernel/l3tl.dtx
index e606c3c558..f3c52e2a0f 100644
--- a/macros/latex/contrib/l3kernel/l3tl.dtx
+++ b/macros/latex/contrib/l3kernel/l3tl.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -187,7 +187,7 @@
% \tl_put_left:co,
% \tl_gput_left:Nn, \tl_gput_left:NV, \tl_gput_left:Nv, \tl_gput_left:Ne,
% \tl_gput_left:No,
-% \tl_gput_left:cn, \tl_gput_left:cV, \tl_gput_left:cv, \tl_gput_left:ce
+% \tl_gput_left:cn, \tl_gput_left:cV, \tl_gput_left:cv, \tl_gput_left:ce,
% \tl_gput_left:co
% }
% \begin{syntax}
@@ -205,7 +205,7 @@
% \tl_put_right:co,
% \tl_gput_right:Nn, \tl_gput_right:NV, \tl_gput_right:Nv, \tl_gput_right:Ne,
% \tl_gput_right:No,
-% \tl_gput_right:cn, \tl_gput_right:cV, \tl_gput_right:cv, \tl_gput_right:ce
+% \tl_gput_right:cn, \tl_gput_right:cV, \tl_gput_right:cv, \tl_gput_right:ce,
% \tl_gput_right:co
% }
% \begin{syntax}
@@ -592,8 +592,8 @@
% \begin{syntax}
% \cs{tl_reverse_items:n} \Arg{token list}
% \end{syntax}
-% Reverses the order of the \meta{items} stored in \meta{tl~var},
-% so that \Arg{item_1}\Arg{item_2}\Arg{item_3} \ldots \Arg{item_n}
+% Reverses the order of the \meta{items} in the \meta{token list},
+% so that \meta{item_1}\meta{item_2}\meta{item_3} \ldots \meta{item_n}
% becomes \Arg{item_n} \ldots{} \Arg{item_3}\Arg{item_2}\Arg{item_1}.
% This process removes any unprotected space within the
% \meta{token list}. Braced token groups are copied without
diff --git a/macros/latex/contrib/l3kernel/l3token.dtx b/macros/latex/contrib/l3kernel/l3token.dtx
index aedde78098..888ceb3601 100644
--- a/macros/latex/contrib/l3kernel/l3token.dtx
+++ b/macros/latex/contrib/l3kernel/l3token.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
@@ -481,6 +481,18 @@
% \end{texnote}
% \end{function}
%
+% \begin{function}[EXP,added = 2023-10-15]{\token_to_catcode:N}
+% \begin{syntax}
+% \cs{token_to_catcode:N} \meta{token}
+% \end{syntax}
+% Converts the given \meta{token} into a number describing its category code.
+% If \meta{token} is a control sequence this expands to $16$. This can't
+% detect the categories $0$ (escape character), $5$ (end of line), $9$
+% (ignored character), $14$ (comment character), or $15$ (invalid character).
+% Control sequences or active characters let to a token of one of the
+% detectable category codes will yield that category.
+% \end{function}
+%
% \section{Token conditionals}
%
% \begin{function}[EXP,pTF]{\token_if_group_begin:N}
@@ -1022,7 +1034,7 @@
% For instance \cs{peek_regex:nTF} \verb"{ abc | [a-z] }" |{ } { }|
% |abc| will only inspect the first token~|a| even though the first
% branch |abc| of the alternative is preferred in functions such as
-% \cs{peek_regex_remove_once:n}. This may have an effect on
+% \cs{peek_regex_remove_once:nTF}. This may have an effect on
% tokenization if the input stream has not yet been tokenized and
% category codes are changed.
% \end{texnote}
@@ -1221,7 +1233,7 @@
% \end{syntax}
% Converts the \meta{char} to the equivalent case-changed character
% as detailed by the function name (see \cs{str_foldcase:n}
-% and \cs{text_titlecase:n} for details of these terms). The case mapping
+% and \cs{text_titlecase_all:n} for details of these terms). The case mapping
% is carried out with no context-dependence (\emph{cf.}~\cs{text_uppercase:n},
% \emph{etc.}) The \texttt{str} versions always generate \enquote{other}
% (category code $12$) characters, whilst the standard versions generate
@@ -1873,6 +1885,66 @@
% \end{macro}
% \end{macro}
%
+% \begin{macro}{\token_to_catcode:N}
+% \begin{macro}{\@@_to_catcode:N}
+% The macro works by comparing the input token with \cs{if_catcode:w} with all
+% valid category codes. Since the most common tokens in an average argument
+% list are of category $11$ or $12$ those are tested first. And since a space
+% and braces are no ordinary |N|-type arguments, and only control sequences
+% let to those categories can match them they are tested last.
+% \begin{macrocode}
+\cs_new:Npn \token_to_catcode:N
+ { \int_value:w \group_align_safe_begin: \@@_to_catcode:N }
+\cs_new:Npn \@@_to_catcode:N #1
+ {
+ \if_catcode:w \exp_not:N #1 \c_catcode_letter_token
+ 11
+ \else:
+ \if_catcode:w \exp_not:N #1 \c_catcode_other_token
+ 12
+ \else:
+ \if_catcode:w \exp_not:N #1 \c_math_toggle_token
+ 3
+ \else:
+ \if_catcode:w \exp_not:N #1 \c_alignment_token
+ 4
+ \else:
+ \if_catcode:w \exp_not:N #1 ##
+ 6
+ \else:
+ \if_catcode:w \exp_not:N #1 \c_math_superscript_token
+ 7
+ \else:
+ \if_catcode:w \exp_not:N #1 \c_math_subscript_token
+ 8
+ \else:
+ \if_catcode:w \exp_not:N #1 \c_group_begin_token
+ 1
+ \else:
+ \if_catcode:w \exp_not:N #1 \c_group_end_token
+ 2
+ \else:
+ \if_catcode:w \exp_not:N #1 \c_space_token
+ 10
+ \else:
+ \token_if_cs:NTF #1 { 16 } { 13 }
+ \fi:
+ \fi:
+ \fi:
+ \fi:
+ \fi:
+ \fi:
+ \fi:
+ \fi:
+ \fi:
+ \fi:
+ \group_align_safe_end:
+ \exp_stop_f:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}
% {
% \c_group_begin_token,
diff --git a/macros/latex/contrib/l3kernel/l3unicode.dtx b/macros/latex/contrib/l3kernel/l3unicode.dtx
index 2161e0963e..54486cc0fa 100644
--- a/macros/latex/contrib/l3kernel/l3unicode.dtx
+++ b/macros/latex/contrib/l3kernel/l3unicode.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-10-10}
+% \date{Released 2023-10-23}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/source3.pdf b/macros/latex/contrib/l3kernel/source3.pdf
index a89fb20da4..13567c5b2a 100644
--- a/macros/latex/contrib/l3kernel/source3.pdf
+++ b/macros/latex/contrib/l3kernel/source3.pdf
Binary files differ
diff --git a/macros/latex/contrib/l3kernel/source3.tex b/macros/latex/contrib/l3kernel/source3.tex
index bd89e29524..bb91c59643 100644
--- a/macros/latex/contrib/l3kernel/source3.tex
+++ b/macros/latex/contrib/l3kernel/source3.tex
@@ -57,7 +57,7 @@ for those people who are interested.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2023-10-10}
+\date{Released 2023-10-23}
\pagenumbering{roman}
\maketitle
diff --git a/macros/latex/contrib/l3kernel/source3body.tex b/macros/latex/contrib/l3kernel/source3body.tex
index 34573d3d64..f76e8f2872 100644
--- a/macros/latex/contrib/l3kernel/source3body.tex
+++ b/macros/latex/contrib/l3kernel/source3body.tex
@@ -517,9 +517,9 @@ logical construct.
\section{\TeX{} concepts not supported by \LaTeX3{}}
-The \TeX{} concept of an \enquote{\cs{outer}} macro is \emph{not supported}
+The \TeX{} concept of an \enquote{\tn{outer}} macro is \emph{not supported}
at all by \LaTeX3{}. As such, the functions provided here may break when
-used on top of \LaTeXe{} if \cs{outer} tokens are used in the arguments.
+used on top of \LaTeXe{} if \tn{outer} tokens are used in the arguments.
\DisableImplementation
@@ -582,6 +582,9 @@ used on top of \LaTeXe{} if \cs{outer} tokens are used in the arguments.
l3fp-trig.dtx ,
l3fp-convert.dtx ,
l3fp-random.dtx ,
+ l3fp-types.dtx ,
+ l3fp-symbolic.dtx ,
+ l3fp-functions.dtx
}
\ExplSyntaxOff