summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-12-18 03:04:42 +0000
committerNorbert Preining <norbert@preining.info>2022-12-18 03:04:42 +0000
commit81dce26929e98696f622283b42f25c643dcfe565 (patch)
tree7b1172ee9247eab226e5d425bc8d42ddea0be53b /macros/latex/contrib/l3kernel
parent7b88c25271448cb717bea52abc52e2c8ec033dd9 (diff)
CTAN sync 202212180304
Diffstat (limited to 'macros/latex/contrib/l3kernel')
-rw-r--r--macros/latex/contrib/l3kernel/CHANGELOG.md24
-rw-r--r--macros/latex/contrib/l3kernel/README.md2
-rw-r--r--macros/latex/contrib/l3kernel/expl3.dtx16
-rw-r--r--macros/latex/contrib/l3kernel/expl3.pdfbin625753 -> 622474 bytes
-rw-r--r--macros/latex/contrib/l3kernel/interface3.pdfbin1776730 -> 1777576 bytes
-rw-r--r--macros/latex/contrib/l3kernel/interface3.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3basics.dtx2
-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.dtx38
-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.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3debug.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3deprecation.dtx91
-rw-r--r--macros/latex/contrib/l3kernel/l3doc.dtx50
-rw-r--r--macros/latex/contrib/l3kernel/l3doc.pdfbin557624 -> 557773 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3docstrip.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3docstrip.pdfbin151363 -> 151535 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.dtx2
-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-logic.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-parse.dtx4
-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-traps.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp-trig.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fp.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3fparray.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3int.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3intarray.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3kernel-functions.dtx49
-rw-r--r--macros/latex/contrib/l3kernel/l3keys.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3legacy.dtx2
-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.pdfbin395879 -> 395876 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news01.pdfbin122710 -> 122710 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news02.pdfbin150676 -> 150674 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news03.pdfbin148702 -> 148706 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news04.pdfbin114588 -> 114586 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news05.pdfbin112487 -> 112485 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news06.pdfbin151573 -> 151569 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news07.pdfbin128309 -> 128316 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news08.pdfbin163454 -> 163456 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news09.pdfbin250139 -> 250136 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news10.pdfbin150279 -> 150283 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news11.pdfbin170063 -> 170076 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3news12.pdfbin204990 -> 204992 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3pdf.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3prefixes.csv1
-rw-r--r--macros/latex/contrib/l3kernel/l3prefixes.pdfbin81626 -> 81614 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3prg.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3prop.dtx34
-rw-r--r--macros/latex/contrib/l3kernel/l3quark.dtx23
-rw-r--r--macros/latex/contrib/l3kernel/l3regex.dtx2
-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.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3str.dtx217
-rw-r--r--macros/latex/contrib/l3kernel/l3styleguide.pdfbin295820 -> 295942 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3styleguide.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3syntax-changes.pdfbin242489 -> 242613 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3syntax-changes.tex2
-rw-r--r--macros/latex/contrib/l3kernel/l3sys.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3term-glossary.pdfbin230896 -> 215155 bytes
-rw-r--r--macros/latex/contrib/l3kernel/l3term-glossary.tex24
-rw-r--r--macros/latex/contrib/l3kernel/l3text-case.dtx2407
-rw-r--r--macros/latex/contrib/l3kernel/l3text-map.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3text-purify.dtx6
-rw-r--r--macros/latex/contrib/l3kernel/l3text.dtx123
-rw-r--r--macros/latex/contrib/l3kernel/l3tl-analysis.dtx2
-rw-r--r--macros/latex/contrib/l3kernel/l3tl.dtx4
-rw-r--r--macros/latex/contrib/l3kernel/l3token.dtx423
-rw-r--r--macros/latex/contrib/l3kernel/l3unicode.dtx824
-rw-r--r--macros/latex/contrib/l3kernel/source3.pdfbin7341222 -> 7318042 bytes
-rw-r--r--macros/latex/contrib/l3kernel/source3.tex2
87 files changed, 1947 insertions, 2509 deletions
diff --git a/macros/latex/contrib/l3kernel/CHANGELOG.md b/macros/latex/contrib/l3kernel/CHANGELOG.md
index 91a9b82c57..7952d03430 100644
--- a/macros/latex/contrib/l3kernel/CHANGELOG.md
+++ b/macros/latex/contrib/l3kernel/CHANGELOG.md
@@ -7,6 +7,20 @@ this project uses date-based 'snapshot' version identifiers.
## [Unreleased]
+## [2022-12-17]
+
+### Added
+- `\codepoint_to_nfd:n`
+- `\codepoint_generate:n` and `\codepoint_str_generate:n`
+- `\str_casefold:n`
+
+### Changed
+- Protect `babel` shorthands from expansion
+
+### Fixed
+- Appearance of `\DescribeOption` (issue
+ [\#1111](https://github.com/latex3/latex3/issues/1111))
+
## [2022-11-02]
### Added
@@ -30,6 +44,13 @@ this project uses date-based 'snapshot' version identifiers.
- Creation of a message with some engines (issue
[\#1139](https://github.com/latex3/latex3/issues/1139))
+### Deprecated
+- `\char_to_nfd:N`, `\char_to_nfd:n`
+- `\char_foldcase:N`, `\char_lowercase:N`, `\char_uppercase:N`
+ and `str` variants
+- `\char_to_utfviii_bytes:n`
+- `\str_foldcase:n`
+
## [2022-09-28]
### Added
@@ -1231,7 +1252,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/2022-11-02...HEAD
+[Unreleased]: https://github.com/latex3/latex3/compare/2022-12-17...HEAD
+[2022-12-17]: https://github.com/latex3/latex3/compare/2022-11-02...2022-12-17
[2022-11-02]: https://github.com/latex3/latex3/compare/2022-10-26...2022-11-02
[2022-10-26]: https://github.com/latex3/latex3/compare/2022-09-28...2022-10-26
[2022-09-28]: https://github.com/latex3/latex3/compare/2022-08-30...2022-09-28
diff --git a/macros/latex/contrib/l3kernel/README.md b/macros/latex/contrib/l3kernel/README.md
index f93c852fbe..8126173a6b 100644
--- a/macros/latex/contrib/l3kernel/README.md
+++ b/macros/latex/contrib/l3kernel/README.md
@@ -1,7 +1,7 @@
LaTeX3 Programming Conventions
==============================
-Release 2022-11-02
+Release 2022-12-17
Overview
--------
diff --git a/macros/latex/contrib/l3kernel/expl3.dtx b/macros/latex/contrib/l3kernel/expl3.dtx
index 91240143e5..01e337fb62 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{2022-11-02}%
+\def\ExplFileDate{2022-12-17}%
%<*driver>
\documentclass[full]{l3doc}
\usepackage{graphicx}
@@ -51,7 +51,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -1182,9 +1182,15 @@
% Identify the package or add to the format message.
% \begin{macrocode}
%<*2ekernel>
-\everyjob\expandafter{\the\everyjob
- \message{L3 programming layer <\ExplFileDate>}%
-}
+\ifdefined\LaTeXReleaseInfo
+ \LaTeXReleaseInfo\expandafter{\the\LaTeXReleaseInfo
+ \show@release@info{L3 programming layer <\ExplFileDate>}%
+ }%
+\else
+ \everyjob\expandafter{\the\everyjob
+ \message{L3 programming layer <\ExplFileDate>}%
+ }%
+\fi
%</2ekernel>
%<*!2ekernel>
\ProvidesPackage{expl3}
diff --git a/macros/latex/contrib/l3kernel/expl3.pdf b/macros/latex/contrib/l3kernel/expl3.pdf
index 0526c9bffd..ea4493fe77 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 22204b77d6..870a0c86ed 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 6d3d96bf29..00518848ed 100644
--- a/macros/latex/contrib/l3kernel/interface3.tex
+++ b/macros/latex/contrib/l3kernel/interface3.tex
@@ -54,7 +54,7 @@ for those people who are interested.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2022-11-02}
+\date{Released 2022-12-17}
\pagenumbering{roman}
\maketitle
diff --git a/macros/latex/contrib/l3kernel/l3basics.dtx b/macros/latex/contrib/l3kernel/l3basics.dtx
index 45fd5cd492..014b134cba 100644
--- a/macros/latex/contrib/l3kernel/l3basics.dtx
+++ b/macros/latex/contrib/l3kernel/l3basics.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3bootstrap.dtx b/macros/latex/contrib/l3kernel/l3bootstrap.dtx
index 2b840ae68e..3ee7509804 100644
--- a/macros/latex/contrib/l3kernel/l3bootstrap.dtx
+++ b/macros/latex/contrib/l3kernel/l3bootstrap.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3box.dtx b/macros/latex/contrib/l3kernel/l3box.dtx
index c80f06ec95..47d18e3e87 100644
--- a/macros/latex/contrib/l3kernel/l3box.dtx
+++ b/macros/latex/contrib/l3kernel/l3box.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3candidates.dtx b/macros/latex/contrib/l3kernel/l3candidates.dtx
index d422a4dc62..5be78d56d7 100644
--- a/macros/latex/contrib/l3kernel/l3candidates.dtx
+++ b/macros/latex/contrib/l3kernel/l3candidates.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -347,7 +347,7 @@
% \begin{function}[EXP, added = 2016-12-06]
% {\prop_rand_key_value:N, \prop_rand_key_value:c}
% \begin{syntax}
-% \cs{prop_rand_key_value:N} \meta{prop~var}
+% \cs{prop_rand_key_value:N} \meta{property list}
% \end{syntax}
% Selects a pseudo-random key--value pair from the \meta{property list}
% and returns \Arg{key} and \Arg{value}. If the \meta{property list} is
@@ -626,40 +626,6 @@
% (\enquote{active}), and character code $32$ (space).
% \end{variable}
%
-% \begin{function}[added = 2020-01-09, EXP]{\char_to_utfviii_bytes:n}
-% \begin{syntax}
-% \cs{char_to_utfviii_bytes:n} \Arg{codepoint}
-% \end{syntax}
-% Converts the (Unicode) \meta{codepoint} to UTF-8 bytes. The expansion
-% of this function comprises four brace groups, each of which will contain
-% a hexadecimal value: the appropriate byte. As UTF-8 is a variable-length,
-% one or more of the groups may be empty: the bytes read in the logical order,
-% such that a two-byte codepoint will have groups |#1| and |#2| filled
-% and |#3| and |#4| empty.
-% \end{function}
-%
-% \begin{function}[added = 2020-01-02, rEXP]{\char_to_nfd:N}
-% \begin{syntax}
-% \cs{char_to_nfd:N} \meta{char}
-% \end{syntax}
-% Converts the \meta{char} to the Unicode Normalization Form Canonical
-% Decomposition. The category code of the \emph{first} generated character is
-% the same as the \meta{char}; second and subsequent chars will have the
-% current category code, as they would if typed in directly. For $8$-bit
-% engines, no change will take place.
-% \end{function}
-%
-% \begin{function}[added = 2022-08-29, rEXP]{\char_to_nfd:n}
-% \begin{syntax}
-% \cs{char_to_nfd:n} \Arg{codepoint}
-% \end{syntax}
-% Converts the (Unicode) \meta{codepoint} to the Unicode Normalization
-% Form Canonical Decomposition. The generated character(s) will have
-% the current category code as they would if typed in directly. In contrast
-% to \cs{char_to_nfd:N}, this function \emph{does} decompose codepoints
-% with $8$-bit engines.
-% \end{function}
-%
% \begin{function}[added = 2018-09-23]
% {
% \peek_catcode_collect_inline:Nn,
diff --git a/macros/latex/contrib/l3kernel/l3cctab.dtx b/macros/latex/contrib/l3kernel/l3cctab.dtx
index a835763025..41f43dc136 100644
--- a/macros/latex/contrib/l3kernel/l3cctab.dtx
+++ b/macros/latex/contrib/l3kernel/l3cctab.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3clist.dtx b/macros/latex/contrib/l3kernel/l3clist.dtx
index 35462cf76a..e798879c14 100644
--- a/macros/latex/contrib/l3kernel/l3clist.dtx
+++ b/macros/latex/contrib/l3kernel/l3clist.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3coffins.dtx b/macros/latex/contrib/l3kernel/l3coffins.dtx
index 263bcadbf1..95a9ab4ee6 100644
--- a/macros/latex/contrib/l3kernel/l3coffins.dtx
+++ b/macros/latex/contrib/l3kernel/l3coffins.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3color.dtx b/macros/latex/contrib/l3kernel/l3color.dtx
index a904ddeaa1..7535b45bd5 100644
--- a/macros/latex/contrib/l3kernel/l3color.dtx
+++ b/macros/latex/contrib/l3kernel/l3color.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -2146,7 +2146,7 @@
{
\exp_args:Nee \@@_model_new:nnn
{ \tl_to_str:n {#1} }
- { \str_foldcase:n {#2} } {#3}
+ { \str_casefold:n {#2} } {#3}
}
\cs_new_protected:Npn \@@_model_new:nnn #1#2#3
{
diff --git a/macros/latex/contrib/l3kernel/l3debug.dtx b/macros/latex/contrib/l3kernel/l3debug.dtx
index aa437dae72..45377dfa27 100644
--- a/macros/latex/contrib/l3kernel/l3debug.dtx
+++ b/macros/latex/contrib/l3kernel/l3debug.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3deprecation.dtx b/macros/latex/contrib/l3kernel/l3deprecation.dtx
index b7db3e0efb..9d6dc6b09a 100644
--- a/macros/latex/contrib/l3kernel/l3deprecation.dtx
+++ b/macros/latex/contrib/l3kernel/l3deprecation.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -468,10 +468,20 @@
\cs_gset:Npn \str_upper_case:n { \str_uppercase:n }
\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_uppercase:f }
\cs_gset:Npn \str_upper_case:f { \str_uppercase:f }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_foldcase:n }
-\cs_gset:Npn \str_fold_case:n { \str_foldcase:n }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_foldcase:V }
-\cs_gset:Npn \str_fold_case:V { \str_foldcase:V }
+\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_casefold:n }
+\cs_gset:Npn \str_fold_case:n { \str_casefold:n }
+\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_casefold:V }
+\cs_gset:Npn \str_fold_case:V { \str_casefold:V }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {\str_foldcase:n, \str_foldcase:V}
+% \begin{macrocode}
+\__kernel_patch_deprecation:nnNNpn { 2020-10-17 } { \str_casefold:n }
+\cs_gset:Npn \str_foldcase:n { \str_casefold:n }
+\__kernel_patch_deprecation:nnNNpn { 2022-10-17 } { \str_casefold:V }
+\cs_gset:Npn \str_foldcase:V { \str_casefold:V }
% \end{macrocode}
% \end{macro}
%
@@ -549,6 +559,22 @@
%
% \subsection{Deprecated \pkg{l3token} functions}
%
+% \begin{macro}[EXP]{\char_to_utfviii_bytes:n}
+% \begin{macrocode}
+\__kernel_patch_deprecation:nnNNpn { 2022-10-09 } { [ \codepoint_generate:n ] }
+\cs_gset:Npn \char_to_utfviii_bytes:n { \__kernel_codepoint_to_bytes:n }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\char_to_nfd:Nm, \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} }
+\__kernel_patch_deprecation:nnNNpn { 2022-10-09 } { \codepoint_to_nfd:n }
+\cs_gset:Npn \char_to_nfd:n { \codepoint_to_nfd:n }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[EXP]
% {
% \char_lower_case:N, \char_upper_case:N,
@@ -557,22 +583,45 @@
% \char_str_mixed_case:Nn, \char_str_fold_case:N,
% }
% \begin{macrocode}
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \char_lowercase:N }
-\cs_gset:Npn \char_lower_case:N { \char_lowercase:N }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \char_uppercase:N }
-\cs_gset:Npn \char_upper_case:N { \char_uppercase:N }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \char_titlecase:N }
-\cs_gset:Npn \char_mixed_case:N { \char_titlecase:N }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \char_foldcase:N }
-\cs_gset:Npn \char_fold_case:N { \char_foldcase:N }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \char_str_lowercase:N }
-\cs_gset:Npn \char_str_lower_case:N { \char_str_lowercase:N }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \char_str_uppercase:N }
-\cs_gset:Npn \char_str_upper_case:N { \char_str_uppercase:N }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \char_str_titlecase:N }
-\cs_gset:Npn \char_str_mixed_case:N { \char_str_titlecase:N }
-\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \char_str_foldcase:N }
-\cs_gset:Npn \char_str_fold_case:N { \char_str_foldcase:N }
+\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \text_lowercase:n }
+\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 } { \str_casefold:n }
+\cs_gset:Npn \char_fold_case:N { \str_casefold:n }
+\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_lowercase:n }
+\cs_gset:Npn \char_str_lower_case:N { \str_lowercase:n }
+\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_uppercase:n }
+\cs_gset:Npn \char_str_upper_case:N { \str_uppercase:n }
+\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_titlecase:n }
+\cs_gset:Npn \char_str_mixed_case:N { \str_titlecase:n }
+\__kernel_patch_deprecation:nnNNpn { 2020-01-03 } { \str_casefold:n }
+\cs_gset:Npn \char_str_fold_case:N { \str_casefold:n }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {
+% \char_lowercase:N, \char_uppercase:N,
+% \char_foldcase:N,
+% \char_str_lowercase:N, \char_str_uppercase:N,
+% \char_str_foldcase:N,
+% }
+% \begin{macrocode}
+\__kernel_patch_deprecation:nnNNpn { 2022-10-17 } { \text_lowercase:n }
+\cs_gset:Npn \char_lowercase:N { \text_lowercase:n }
+\__kernel_patch_deprecation:nnNNpn { 2022-10-17 } { \text_uppercase:n }
+\cs_gset:Npn \char_uppercase:N { \text_uppercase:n }
+\__kernel_patch_deprecation:nnNNpn { 2022-10-17 } { \str_casefold:n }
+\cs_gset:Npn \char_foldcase:N { \str_casefold:n }
+\__kernel_patch_deprecation:nnNNpn { 2022-10-17 } { \str_lowercase:n }
+\cs_gset:Npn \char_str_lowercase:N { \str_lowercase:n }
+\__kernel_patch_deprecation:nnNNpn { 2022-10-17 } { \str_uppercase:n }
+\cs_gset:Npn \char_str_uppercase:N { \str_uppercase:n }
+\__kernel_patch_deprecation:nnNNpn { 2022-10-17 } { \str_casefold:n }
+\cs_gset:Npn \char_str_foldcase:N { \str_casefold:n }
% \end{macrocode}
% \end{macro}
%
diff --git a/macros/latex/contrib/l3kernel/l3doc.dtx b/macros/latex/contrib/l3kernel/l3doc.dtx
index 78a9412025..224b1aaead 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 2022-11-02}
+% \date{Released 2022-12-17}
% \maketitle
% \tableofcontents
%
@@ -3410,52 +3410,10 @@ and all files in that bundle must be distributed together.
% \subsubsection{Misc}
%
% \begin{macro}{\DescribeOption}
-% For describing package options. Due to Joseph Wright. Name/usage
-% might change soon.
+% For describing package options: retained for consistency, but updated for
+% \pkg{doc}~v3.
% \begin{macrocode}
-\newcommand*{\DescribeOption}
- {
- \leavevmode
- \@bsphack
- \begingroup
- \MakePrivateLetters
- \Describe@Option
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\newcommand*{\Describe@Option}[1]
- {
- \endgroup
- \marginpar{
- \raggedleft
- \PrintDescribeEnv{#1}
- }
- \SpecialOptionIndex{#1}
- \@esphack
- \ignorespaces
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\newcommand*{\SpecialOptionIndex}[1]
- {
- \@bsphack
- \begingroup
- \@@_target:
- \index
- {
- #1\actualchar{\protect\ttfamily#1}~(option)
- \encapchar hdclindex{\the\c@HD@hypercount}{usage}
- }
- \index
- {
- options:\levelchar#1\actualchar{\protect\ttfamily#1}
- \encapchar hdclindex{\the\c@HD@hypercount}{usage}
- }
- \endgroup
- \@esphack
- }
+\NewDocElement[idxtype = option, idxgroup = options]{Option}{optionenv}
% \end{macrocode}
% \end{macro}
%
diff --git a/macros/latex/contrib/l3kernel/l3doc.pdf b/macros/latex/contrib/l3kernel/l3doc.pdf
index 9b8c5d1ab9..dd28a7c8ec 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 7708f045e4..55498a07d7 100644
--- a/macros/latex/contrib/l3kernel/l3docstrip.dtx
+++ b/macros/latex/contrib/l3kernel/l3docstrip.dtx
@@ -63,7 +63,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3docstrip.pdf b/macros/latex/contrib/l3kernel/l3docstrip.pdf
index 1b744af08b..d63049b0ad 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 788143f549..218e673d5c 100644
--- a/macros/latex/contrib/l3kernel/l3expan.dtx
+++ b/macros/latex/contrib/l3kernel/l3expan.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3file.dtx b/macros/latex/contrib/l3kernel/l3file.dtx
index 55a83f486e..d541aa574e 100644
--- a/macros/latex/contrib/l3kernel/l3file.dtx
+++ b/macros/latex/contrib/l3kernel/l3file.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3flag.dtx b/macros/latex/contrib/l3kernel/l3flag.dtx
index 517ebfb46a..afcaffd7ad 100644
--- a/macros/latex/contrib/l3kernel/l3flag.dtx
+++ b/macros/latex/contrib/l3kernel/l3flag.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-assign.dtx b/macros/latex/contrib/l3kernel/l3fp-assign.dtx
index 0a6ea7325d..fccec11696 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 2022-11-02}
+% \date{Released 2022-12-17}
% \maketitle
%
% \begin{documentation}
diff --git a/macros/latex/contrib/l3kernel/l3fp-aux.dtx b/macros/latex/contrib/l3kernel/l3fp-aux.dtx
index 48696082c6..4a1af5bfe5 100644
--- a/macros/latex/contrib/l3kernel/l3fp-aux.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-aux.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-basics.dtx b/macros/latex/contrib/l3kernel/l3fp-basics.dtx
index 71f166ceca..67cf7d43c7 100644
--- a/macros/latex/contrib/l3kernel/l3fp-basics.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-basics.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-convert.dtx b/macros/latex/contrib/l3kernel/l3fp-convert.dtx
index 515c1b3ab9..dc98c5fdf0 100644
--- a/macros/latex/contrib/l3kernel/l3fp-convert.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-convert.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-expo.dtx b/macros/latex/contrib/l3kernel/l3fp-expo.dtx
index 8b816a222f..93d79258f1 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 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-extended.dtx b/macros/latex/contrib/l3kernel/l3fp-extended.dtx
index 8b592233dd..3528e7bb44 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 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-logic.dtx b/macros/latex/contrib/l3kernel/l3fp-logic.dtx
index 52f1e9b8bc..d4571626de 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 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-parse.dtx b/macros/latex/contrib/l3kernel/l3fp-parse.dtx
index 2f0fccdc23..6ece846860 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 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -1023,7 +1023,7 @@
\cs_if_exist_use:cF { @@_parse_word_#2:N }
{
\cs_if_exist_use:cF
- { @@_parse_caseless_ \str_foldcase:n {#2} :N }
+ { @@_parse_caseless_ \str_casefold:n {#2} :N }
{
\msg_expandable_error:nnn
{ fp } { unknown-fp-word } {#2}
diff --git a/macros/latex/contrib/l3kernel/l3fp-random.dtx b/macros/latex/contrib/l3kernel/l3fp-random.dtx
index 04bd5285b0..732bcc657c 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 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-round.dtx b/macros/latex/contrib/l3kernel/l3fp-round.dtx
index 65db824b79..45514ebdef 100644
--- a/macros/latex/contrib/l3kernel/l3fp-round.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-round.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp-traps.dtx b/macros/latex/contrib/l3kernel/l3fp-traps.dtx
index 6863f69abc..df2ba96aee 100644
--- a/macros/latex/contrib/l3kernel/l3fp-traps.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp-traps.dtx
@@ -40,7 +40,7 @@
% {latex-team@latex-project.org}^^A
% }^^A
% }
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
% \maketitle
%
% \begin{documentation}
diff --git a/macros/latex/contrib/l3kernel/l3fp-trig.dtx b/macros/latex/contrib/l3kernel/l3fp-trig.dtx
index 7b7129d7f4..f7d669a2a2 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 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fp.dtx b/macros/latex/contrib/l3kernel/l3fp.dtx
index 59e97b0648..efb246efe7 100644
--- a/macros/latex/contrib/l3kernel/l3fp.dtx
+++ b/macros/latex/contrib/l3kernel/l3fp.dtx
@@ -49,7 +49,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3fparray.dtx b/macros/latex/contrib/l3kernel/l3fparray.dtx
index 2b21ad7ff4..7d5a54e4a0 100644
--- a/macros/latex/contrib/l3kernel/l3fparray.dtx
+++ b/macros/latex/contrib/l3kernel/l3fparray.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3int.dtx b/macros/latex/contrib/l3kernel/l3int.dtx
index 0d45445773..c8342428f1 100644
--- a/macros/latex/contrib/l3kernel/l3int.dtx
+++ b/macros/latex/contrib/l3kernel/l3int.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3intarray.dtx b/macros/latex/contrib/l3kernel/l3intarray.dtx
index 9d71901191..78701c1dc9 100644
--- a/macros/latex/contrib/l3kernel/l3intarray.dtx
+++ b/macros/latex/contrib/l3kernel/l3intarray.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3kernel-functions.dtx b/macros/latex/contrib/l3kernel/l3kernel-functions.dtx
index 6a5a81e6ef..143231de87 100644
--- a/macros/latex/contrib/l3kernel/l3kernel-functions.dtx
+++ b/macros/latex/contrib/l3kernel/l3kernel-functions.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -105,6 +105,18 @@
% all of these tests succeed then the \meta{true code} is run.
% \end{function}
%
+% \begin{function}[EXP]{\__kernel_codepoint_to_bytes:n}
+% \begin{syntax}
+% \cs{__kernel_codepoint_to_bytes:n} \Arg{codepoint}
+% \end{syntax}
+% Converts the \meta{codepoint} to UTF-8 bytes. The expansion
+% of this function comprises four brace groups, each of which will contain
+% a hexadecimal value: the appropriate byte. As UTF-8 is a variable-length,
+% one or more of the groups may be empty: the bytes read in the logical order,
+% such that a two-byte codepoint will have groups |#1| and |#2| filled
+% and |#3| and |#4| empty.
+% \end{function}
+%
% \begin{function}{\__kernel_cs_parm_from_arg_count:nnF}
% \begin{syntax}
% \cs{__kernel_cs_parm_from_arg_count:nnF} \Arg{follow-on} \Arg{args} \Arg{false code}
@@ -477,6 +489,41 @@
% \meta{tl~var} and \meta{tokens}.
% \end{function}
%
+% \begin{function}[EXP]{\__kernel_codepoint_data:nn}
+% \begin{syntax}
+% \cs{__kernel_codepoint_data:nn} \Arg{type} \Arg{codepoint}
+% \end{syntax}
+% Expands to the appropriate value for the \meta{type} of data
+% requested for a \meta{codepoint}. The current list of \meta{types} and
+% results are
+% \begin{description}
+% \item[\texttt{lowercase}] The \emph{single} codepoint specified by
+% \texttt{UnicodeData.txt} for lowercase mapping of the codepoint:
+% will be equal to the input \meta{codepoint} if there is no mapping
+% specified in \texttt{UnicodeData.txt}
+% \item[\texttt{uppercase}] The \emph{single} codepoint specified by
+% \texttt{UnicodeData.txt} for uppercase mapping of the codepoint:
+% will be equal to the input \meta{codepoint} if there is no mapping
+% specified in \texttt{UnicodeData.txt}
+% \end{description}
+% \end{function}
+%
+% \begin{function}[EXP]{\__kernel_codepoint_case:nn}
+% \begin{syntax}
+% \cs{__kernel_codepoint_case:nn} \Arg{mapping} \Arg{codepoint}
+% \end{syntax}
+% Expands to a list of three balanced text, of which at least the first
+% will contain a codepoint. This list of up to three codepoints specifies
+% the full case mapping for the input \meta{codepoint}. The \meta{mapping}
+% should be one of
+% \begin{itemize}
+% \item \texttt{casefold}
+% \item \texttt{lowercase}
+% \item \texttt{titlecase}
+% \item \texttt{uppercase}
+% \end{itemize}
+% \end{function}
+%
% \subsection{Kernel backend functions}
%
% These functions are required to pass information to the backend. The nature
diff --git a/macros/latex/contrib/l3kernel/l3keys.dtx b/macros/latex/contrib/l3kernel/l3keys.dtx
index 9852a753d8..71667e2d7b 100644
--- a/macros/latex/contrib/l3kernel/l3keys.dtx
+++ b/macros/latex/contrib/l3kernel/l3keys.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3legacy.dtx b/macros/latex/contrib/l3kernel/l3legacy.dtx
index 089e86c018..df626bb4be 100644
--- a/macros/latex/contrib/l3kernel/l3legacy.dtx
+++ b/macros/latex/contrib/l3kernel/l3legacy.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3luatex.dtx b/macros/latex/contrib/l3kernel/l3luatex.dtx
index 2b061e4f0e..78a8e07339 100644
--- a/macros/latex/contrib/l3kernel/l3luatex.dtx
+++ b/macros/latex/contrib/l3kernel/l3luatex.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3msg.dtx b/macros/latex/contrib/l3kernel/l3msg.dtx
index 6a0bf9ff19..d4fc2f55c7 100644
--- a/macros/latex/contrib/l3kernel/l3msg.dtx
+++ b/macros/latex/contrib/l3kernel/l3msg.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3names.dtx b/macros/latex/contrib/l3kernel/l3names.dtx
index 1a98cb6bcf..96373ef311 100644
--- a/macros/latex/contrib/l3kernel/l3names.dtx
+++ b/macros/latex/contrib/l3kernel/l3names.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3news.pdf b/macros/latex/contrib/l3kernel/l3news.pdf
index 8a77fbdc78..160f2697c6 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 1c7968aa22..c6b2d9848b 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 b246291c8b..9467dde377 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 0d916b022d..18d37d2382 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 b8c5573d59..757e848070 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 d4c99c59af..ccd814f681 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 99efa5b462..e10d0b9c9d 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 70f5efb753..5f970f1755 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 f2305506a0..1b931f862a 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 d426dba685..41f5542562 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 87c6b75bb0..370eb06cf4 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 113a3a3cef..e8162c9a05 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 1207717863..37bda3fe3a 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 8a359528d9..c29dbe4141 100644
--- a/macros/latex/contrib/l3kernel/l3pdf.dtx
+++ b/macros/latex/contrib/l3kernel/l3pdf.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3prefixes.csv b/macros/latex/contrib/l3kernel/l3prefixes.csv
index 31d77835d4..c69216e094 100644
--- a/macros/latex/contrib/l3kernel/l3prefixes.csv
+++ b/macros/latex/contrib/l3kernel/l3prefixes.csv
@@ -41,6 +41,7 @@ cmd,latex2e,The LaTeX Project,https://www.latex-project.org/latex3.html,https://
code,l3kernel,The LaTeX Project,https://www.latex-project.org/latex3.html,https://github.com/latex3/latex3.git,https://github.com/latex3/latex3/issues,2021-04-23,2021-04-23,
codedoc,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,Somewhat experimental: may change
codehigh,codehigh,Jianrui Lyu,https://github.com/lvjr/codehigh,https://github.com/lvjr/codehigh.git,https://github.com/lvjr/codehigh/issues,2022-04-02,2022-04-02,
+codepoint,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,
coffin,"l3kernel,xcoffins",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,
colon,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,
color,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,
diff --git a/macros/latex/contrib/l3kernel/l3prefixes.pdf b/macros/latex/contrib/l3kernel/l3prefixes.pdf
index 0290386f55..a965d3d543 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 3b50dee107..65e89f9b4b 100644
--- a/macros/latex/contrib/l3kernel/l3prg.dtx
+++ b/macros/latex/contrib/l3kernel/l3prg.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3prop.dtx b/macros/latex/contrib/l3kernel/l3prop.dtx
index c124459362..0cc1c3730b 100644
--- a/macros/latex/contrib/l3kernel/l3prop.dtx
+++ b/macros/latex/contrib/l3kernel/l3prop.dtx
@@ -43,13 +43,13 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
% \begin{documentation}
%
-% \LaTeX3 implements a \enquote{property list} data type, which contain
+% \pkg{expl3} implements a \meta{property list} data type, which contain
% an unordered list of entries each of which consists of a \meta{key} and
% an associated \meta{value}. The \meta{key} and \meta{value} may both
% be any \meta{balanced text}, the \meta{key} is processed using
@@ -117,13 +117,13 @@
% \prop_gset_from_keyval:Nn, \prop_gset_from_keyval:cn,
% }
% \begin{syntax}
-% \cs{prop_set_from_keyval:Nn} \meta{prop~var}
+% \cs{prop_set_from_keyval:Nn} \meta{property list}
% \{
% \meta{key1} |=| \meta{value1} |,|
% \meta{key2} |=| \meta{value2} |,| \ldots{}
% \}
% \end{syntax}
-% Sets \meta{prop~var} to contain key--value pairs given in the second
+% Sets \meta{property list} to contain key--value pairs given in the second
% argument. If duplicate keys appear only the last of the values is kept.
%
% Spaces are trimmed around every \meta{key} and every \meta{value},
@@ -142,14 +142,14 @@
% \begin{function}[added = 2017-11-28, updated = 2021-11-07]
% {\prop_const_from_keyval:Nn, \prop_const_from_keyval:cn}
% \begin{syntax}
-% \cs{prop_const_from_keyval:Nn} \meta{prop~var}
+% \cs{prop_const_from_keyval:Nn} \meta{property list}
% \{
% \meta{key1} |=| \meta{value1} |,|
% \meta{key2} |=| \meta{value2} |,| \ldots{}
% \}
% \end{syntax}
-% Creates a new constant \meta{prop~var} or raises an error if the
-% name is already taken. The \meta{prop~var} is set globally to
+% Creates a new constant \meta{property list} or raises an error if the
+% name is already taken. The \meta{property list} is set globally to
% contain key--value pairs given in the second argument, processed in
% the way described for \cs{prop_set_from_keyval:Nn}. If duplicate
% keys appear only the last of the values is kept.
@@ -209,12 +209,12 @@
% \prop_gconcat:NNN, \prop_gconcat:ccc
% }
% \begin{syntax}
-% \cs{prop_concat:NNN} \meta{prop~var_1} \meta{prop~var_2} \meta{prop~var_3}
+% \cs{prop_concat:NNN} \meta{property list_1} \meta{property list_2} \meta{property list3}
% \end{syntax}
-% Combines the key--value pairs of \meta{prop~var_2} and
-% \meta{prop~var_3}, and saves the result in \meta{prop~var_1}. If a
-% key appears in both \meta{prop~var_2} and \meta{prop~var_3} then the
-% last value, namely the value in \meta{prop~var_3} is kept.
+% Combines the key--value pairs of \meta{property list_2} and
+% \meta{property list_3}, and saves the result in \meta{pproperty list_1}. If a
+% key appears in both \meta{property list_2} and \meta{property list_3} then the
+% last value, namely the value in \meta{property list_3} is kept.
% \end{function}
%
% \begin{function}[added = 2021-05-16, updated = 2021-11-07]
@@ -223,22 +223,22 @@
% \prop_gput_from_keyval:Nn, \prop_gput_from_keyval:cn,
% }
% \begin{syntax}
-% \cs{prop_put_from_keyval:Nn} \meta{prop~var}
+% \cs{prop_put_from_keyval:Nn} \meta{property list}
% \{
% \meta{key1} |=| \meta{value1} |,|
% \meta{key2} |=| \meta{value2} |,| \ldots{}
% \}
% \end{syntax}
-% Updates the \meta{prop~var} by adding entries for each key--value
+% Updates the \meta{property list} by adding entries for each key--value
% pair given in the second argument. The addition is done through
-% \cs{prop_put:Nnn}, hence if the \meta{prop~var} already contains
+% \cs{prop_put:Nnn}, hence if the \meta{property list} already contains
% some of the keys, the corresponding values are discarded and
% replaced by those given in the key--value list. If duplicate keys
% appear in the key--value list then only the last of the values is kept.
%
% The function is equivalent to storing the key--value pairs in a
-% temporary property variable using \cs{prop_set_from_keyval:Nn}, then
-% combining \meta{prop~var} with the temporary variable using
+% temporary property list using \cs{prop_set_from_keyval:Nn}, then
+% combining \meta{property list} with the temporary variable using
% \cs{prop_concat:NNN}. In particular, the \meta{keys} and
% \meta{values} are space-trimmed and unbraced as described in
% \cs{prop_set_from_keyval:Nn}.
diff --git a/macros/latex/contrib/l3kernel/l3quark.dtx b/macros/latex/contrib/l3kernel/l3quark.dtx
index 05291a288f..9d3cd27c41 100644
--- a/macros/latex/contrib/l3kernel/l3quark.dtx
+++ b/macros/latex/contrib/l3kernel/l3quark.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -942,15 +942,6 @@
%<@@=scan>
% \end{macrocode}
%
-% \begin{variable}{\g_@@_marks_tl}
-% \UnitTested
-% The list of all scan marks currently declared.
-% No \pkg{l3tl} yet, so define this by hand.
-% \begin{macrocode}
-\cs_gset:Npn \g_@@_marks_tl { }
-% \end{macrocode}
-% \end{variable}
-%
% \begin{macro}{\scan_new:N}
% \UnitTested
% Check whether the variable is already a scan mark,
@@ -972,26 +963,30 @@
% \end{macro}
%
% \begin{variable}{\s_stop}
+% \begin{variable}{\g_@@_marks_tl}
% \UnitTested
% We only declare one scan mark here, more can be defined
% by specific modules.
% Can't use \cs{scan_new:N} yet because \pkg{l3tl} isn't loaded,
% so define \cs{s_stop} by hand and add it to \cs{g_@@_marks_tl}.
-% We also add \cs{s__quark} (declared earlier) to the pool here.
-% Since it lives in a different namespace, a little \pkg{l3docstrip}
+% We also add the scan marks declared earlier to the pool here.
+% Since they lives in a different namespace, a little \pkg{l3docstrip}
% cheating is necessary.
% \begin{macrocode}
\cs_new_eq:NN \s_stop \scan_stop:
-\cs_gset_nopar:Npx \g_@@_marks_tl
+\cs_gset_nopar:Npn \g_@@_marks_tl
{
- \exp_not:o \g_@@_marks_tl
\s_stop
%<@@=quark>
\s_@@
+%<@@=cs>
+ \s_@@_mark
+ \s_@@_stop
%<@@=scan>
}
% \end{macrocode}
% \end{variable}
+% \end{variable}
%
% \begin{macro}[EXP]{\use_none_delimit_by_s_stop:w}
% \UnitTested
diff --git a/macros/latex/contrib/l3kernel/l3regex.dtx b/macros/latex/contrib/l3kernel/l3regex.dtx
index 9a42b6badc..720efab1e2 100644
--- a/macros/latex/contrib/l3kernel/l3regex.dtx
+++ b/macros/latex/contrib/l3kernel/l3regex.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3seq.dtx b/macros/latex/contrib/l3kernel/l3seq.dtx
index 4251d71330..36cfb7e9b0 100644
--- a/macros/latex/contrib/l3kernel/l3seq.dtx
+++ b/macros/latex/contrib/l3kernel/l3seq.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3skip.dtx b/macros/latex/contrib/l3kernel/l3skip.dtx
index aa2066c487..d111a3ae5d 100644
--- a/macros/latex/contrib/l3kernel/l3skip.dtx
+++ b/macros/latex/contrib/l3kernel/l3skip.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3sort.dtx b/macros/latex/contrib/l3kernel/l3sort.dtx
index cc6dd07f8f..4fb92cda08 100644
--- a/macros/latex/contrib/l3kernel/l3sort.dtx
+++ b/macros/latex/contrib/l3kernel/l3sort.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3str-convert.dtx b/macros/latex/contrib/l3kernel/l3str-convert.dtx
index 3e3a2a6080..1b3800d9e0 100644
--- a/macros/latex/contrib/l3kernel/l3str-convert.dtx
+++ b/macros/latex/contrib/l3kernel/l3str-convert.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -2635,7 +2635,7 @@
\cs_new:Npn \@@_convert_pdfname_bytes:n #1
{
\exp_args:Ne \@@_convert_pdfname_bytes_aux:n
- { \char_to_utfviii_bytes:n {`#1} }
+ { \__kernel_codepoint_to_bytes:n {`#1} }
}
\cs_new:Npn \@@_convert_pdfname_bytes_aux:n #1
{ \@@_convert_pdfname_bytes_aux:nnnn #1 }
diff --git a/macros/latex/contrib/l3kernel/l3str.dtx b/macros/latex/contrib/l3kernel/l3str.dtx
index 4b240c2aa3..3e8882fb3c 100644
--- a/macros/latex/contrib/l3kernel/l3str.dtx
+++ b/macros/latex/contrib/l3kernel/l3str.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -744,7 +744,7 @@
%
% These functions should \emph{not} be used for
% \begin{itemize}
-% \item Caseless comparisons: use \cs{str_foldcase:n} for this
+% \item Caseless comparisons: use \cs{str_casefold:n} for this
% situation (case folding is distinct from lower casing).
% \item Case changing text for typesetting: see the
% \cs[index=text_lowercase:n]{text_lowercase:n(n)},
@@ -755,10 +755,10 @@
% \end{itemize}
% \end{function}
%
-% \begin{function}[EXP, added = 2019-11-26]
-% {\str_foldcase:n, \str_foldcase:V}
+% \begin{function}[EXP, added = 2022-10-16]
+% {\str_casefold:n, \str_casefold:V}
% \begin{syntax}
-% \cs{str_foldcase:n} \Arg{tokens}
+% \cs{str_casefold:n} \Arg{tokens}
% \end{syntax}
% Converts the input \meta{tokens} to their string representation, as
% described for \cs{tl_to_str:n}, and then folds the case of the resulting
@@ -766,7 +766,7 @@
% left in the input stream.
%
% String folding is a process used for material such as identifiers rather
-% than for \enquote{text}. The folding provided by \cs{str_foldcase:n}
+% than for \enquote{text}. The folding provided by \cs{str_casefold:n}
% follows the mappings provided by the \href{http://www.unicode.org}^^A
% {Unicode Consortium}, who
% \href{http://www.unicode.org/faq/casemap_charprop.html#2}{state}:
@@ -779,7 +779,7 @@
% should be used solely for internal processing and generally should not be
% stored or displayed to the end user.
% \end{quote}
-% The folding approach implemented by \cs{str_foldcase:n} follows the
+% The folding approach implemented by \cs{str_casefold:n} follows the
% \enquote{full} scheme defined by the Unicode Consortium
% (\emph{e.g.}~\SS folds to \texttt{SS}). As case-folding is
% a language-insensitive process, there is no special treatment of
@@ -843,6 +843,16 @@
% code and so should only be used for short-term storage.
% \end{variable}
%
+% \section{Deprecated functions}
+%
+% \begin{function}[EXP, added = 2019-11-26]
+% {\str_foldcase:n, \str_foldcase:V}
+% \begin{syntax}
+% \cs{str_foldcase:n} \Arg{tokens}
+% \end{syntax}
+% A previous name for the functionally-identical \cs{str_casefold:n}.
+% \end{function}
+%
% \end{documentation}
%
% \begin{implementation}
@@ -1896,7 +1906,7 @@
%
% \begin{macro}[EXP]
% {
-% \str_foldcase:n, \str_foldcase:V,
+% \str_casefold:n, \str_casefold:V,
% \str_lowercase:n, \str_lowercase:f,
% \str_uppercase:n, \str_uppercase:f
% }
@@ -1907,27 +1917,23 @@
% \begin{macro}[EXP]{\@@_change_case_end:nw}
% \begin{macro}[EXP]{\@@_change_case_loop:nw}
% \begin{macro}[EXP]{\@@_change_case_space:n}
-% \begin{macro}[EXP]{\@@_change_case_char:nN}
-% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nNN}
-% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nNNN}
-% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nNNNN}
-% \begin{macro}[EXP]
-% {
-% \@@_change_case_char_UTFviii:nn ,
-% \@@_change_case_char_UTFviii_lower:nn ,
-% \@@_change_case_char_UTFviii_upper:nn ,
-% \@@_change_case_char_UTFviii_fold:nn
-% }
+% \begin{macro}[EXP]{\@@_change_case_char:nN, \@@_change_case_char_aux:nN}
+% \begin{macro}[EXP]{\@@_change_case_codepoint:nN}
+% \begin{macro}[EXP]{\@@_change_case_codepoint:nNN}
+% \begin{macro}[EXP]{\@@_change_case_codepoint:nNNN}
+% \begin{macro}[EXP]{\@@_change_case_codepoint:nNNNN}
+% \begin{macro}[EXP]{\@@_change_case_char:nnn, \@@_change_case_char_aux:nnn}
+% \begin{macro}[EXP]{\@@_change_case_char:nnnnn}
% Case changing for programmatic reasons is done by first detokenizing
% input then doing a simple loop that only has to worry about spaces
% and everything else. The output is detokenized to allow data sharing
% with text-based case changing. Similarly, for $8$-bit engines the
% multi-byte information is shared.
% \begin{macrocode}
-\cs_new:Npn \str_foldcase:n #1 { \@@_change_case:nn {#1} { fold } }
-\cs_new:Npn \str_lowercase:n #1 { \@@_change_case:nn {#1} { lower } }
-\cs_new:Npn \str_uppercase:n #1 { \@@_change_case:nn {#1} { upper } }
-\cs_generate_variant:Nn \str_foldcase:n { V }
+\cs_new:Npn \str_casefold:n #1 { \@@_change_case:nn {#1} { casefold } }
+\cs_new:Npn \str_lowercase:n #1 { \@@_change_case:nn {#1} { lowercase } }
+\cs_new:Npn \str_uppercase:n #1 { \@@_change_case:nn {#1} { uppercase } }
+\cs_generate_variant:Nn \str_casefold:n { V }
\cs_generate_variant:Nn \str_lowercase:n { f }
\cs_generate_variant:Nn \str_uppercase:n { f }
\cs_new:Npn \@@_change_case:nn #1
@@ -1962,99 +1968,90 @@
{
\@@_if_recursion_tail_stop_do:Nn #2
{ \@@_change_case_end:wn }
- \@@_change_case_output:fw
- { \use:c { char_str_ #1 case:N } #2 }
- \@@_change_case_loop:nw {#1}
+ \@@_change_case_codepoint:nN {#1} #2
}
\if_int_compare:w 0
\cs_if_exist:NT \tex_XeTeXversion:D { 1 }
\cs_if_exist:NT \tex_luatexversion:D { 1 }
> 0 \exp_stop_f:
+ \cs_new:Npn \@@_change_case_codepoint:nN #1#2
+ { \@@_change_case_char:fnn { \int_eval:n {`#2} } {#1} {#2} }
\else:
- \cs_gset:Npn \@@_change_case_char:nN #1#2
- {
- \@@_if_recursion_tail_stop_do:Nn #2
- { \@@_change_case_end:wn }
- \int_compare:nNnTF { `#2 } > { "80 }
- {
- \int_compare:nNnTF { `#2 } < { "E0 }
- { \@@_change_case_char_UTFviii:nNN }
- {
- \int_compare:nNnTF { `#2 } < { "F0 }
- { \@@_change_case_char_UTFviii:nNNN }
- { \@@_change_case_char_UTFviii:nNNNN }
- }
- {#1} #2
- }
- {
- \@@_change_case_output:fw
- { \use:c { char_str_ #1 case:N } #2 }
- \@@_change_case_loop:nw {#1}
- }
- }
- \cs_new:Npn \@@_change_case_char_UTFviii:nNN #1#2#3
- { \@@_change_case_char_UTFviii:nn {#1} {#2#3} }
- \cs_new:Npn \@@_change_case_char_UTFviii:nNNN #1#2#3#4
- { \@@_change_case_char_UTFviii:nn {#1} {#2#3#4} }
- \cs_new:Npn \@@_change_case_char_UTFviii:nNNNN #1#2#3#4#5
- { \@@_change_case_char_UTFviii:nn {#1} {#2#3#4#5} }
-% \end{macrocode}
-% Skip high chars for the Japanese engines.
-% \begin{macrocode}
- \cs_if_exist:NF \tex_pdftexversion:D
- {
- \cs_gset:Npn \@@_change_case_char_UTFviii:nNNN #1#2#3#4
- {
- \@@_change_case_output:nw {#2#3#4}
- \@@_change_case_loop:nw {#1}
- }
- \cs_gset:Npn \@@_change_case_char_UTFviii:nNNNN #1#2#3#4#5
- {
- \@@_change_case_output:nw {#2#3#4#5}
- \@@_change_case_loop:nw {#1}
- }
- }
- \cs_new:Npn \@@_change_case_char_UTFviii:nn #1#2
- {
- \use:c { @@_change_case_char_UTFviii_ #1 :nn } {#1} {#2}
- }
- \cs_new:Npn \@@_change_case_char_UTFviii_upper:nn #1#2
- {
- \@@_change_case_output:fw
- {
- \cs_if_exist:cTF { c__kernel_ #1 case_ #2 _tl }
- {
- \__kernel_tl_to_str:w \exp_after:wN \exp_after:wN \exp_after:wN
- { \cs:w c__kernel_ #1 case_ #2 _tl \cs_end: }
- }
- {#2}
- }
- \@@_change_case_loop:nw {#1}
- }
- \cs_new_eq:NN \@@_change_case_char_UTFviii_lower:nn
- \@@_change_case_char_UTFviii_upper:nn
- \cs_new:Npn \@@_change_case_char_UTFviii_fold:nn #1#2
- {
- \@@_change_case_output:fw
- {
- \cs_if_exist:cTF { c__kernel_ #1 case_ #2 _tl }
- {
- \__kernel_tl_to_str:w \exp_after:wN \exp_after:wN \exp_after:wN
- { \cs:w c__kernel_ #1 case_ #2 _tl \cs_end: }
- }
- {
- \cs_if_exist:cTF { c__kernel_lowercase_ #2 _tl }
- {
- \__kernel_tl_to_str:w
- \exp_after:wN \exp_after:wN \exp_after:wN
- { \cs:w c__kernel_lowercase_ #2 _tl \cs_end: }
- }
- {#2}
- }
- }
- \@@_change_case_loop:nw {#1}
- }
+ \cs_new:Npn \@@_change_case_codepoint:nN #1#2
+ {
+ \int_compare:nNnTF {`#2} > { "80 }
+ {
+ \int_compare:nNnTF {`#2} < { "E0 }
+ { \@@_change_case_codepoint:nNN }
+ {
+ \int_compare:nNnTF {`#2} < { "F0 }
+ { \@@_change_case_codepoint:nNNN }
+ { \@@_change_case_codepoint:nNNNNN }
+ }
+ }
+ { \@@_change_case_char_aux:nN }
+ {#1} #2
+ }
+ \cs_new:Npn \@@_change_case_char_aux:nN #1#2
+ { \@@_change_case_char:fnn { \int_eval:n {`#2} } {#1} {#2} }
+ \cs_new:Npn \@@_change_case_codepoint:nNN #1#2#3
+ {
+ \@@_change_case_char:fnn
+ { \int_eval:n { (`#2 - "C0) * "40 + `#3 - "80 } }
+ {#1} {#2#3}
+ }
+ \cs_new:Npn \@@_change_case_codepoint:nNNN #1#2#3#4
+ {
+ \@@_change_case_char:fnn
+ {
+ \int_eval:n
+ { (`#2 - "E0) * "1000 + (`#3 - "80) * "40 + `#4 - "80 }
+ }
+ {#1} {#2#3#4}
+ }
+ \cs_new:Npn \@@_change_case_codepoint:nNNNN #1#2#3#4#5
+ {
+ \@@_change_case_char:fnn
+ {
+ \int_eval:n
+ {
+ (`#2 - "F0) * "40000
+ + (`#3 - "80) * "1000
+ + (`#4 - "80) * "40
+ + `#5 - "80
+ }
+ }
+ {#1} {#2#3#4#5}
+ }
\fi:
+\cs_new:Npn \@@_change_case_char:nnn #1#2#3
+ {
+ \@@_change_case_output:fw
+ {
+ \exp_args:Ne \@@_change_case_char_aux:nnn
+ { \__kernel_codepoint_case:nn {#2} {#1} } {#1} {#3}
+ }
+ \@@_change_case_loop:nw {#2}
+ }
+\cs_generate_variant:Nn \@@_change_case_char:nnn { f }
+\cs_new:Npn \@@_change_case_char_aux:nnn #1#2#3
+ {
+ \use:e { \@@_change_case_char:nnnnn #1 {#2} {#3} }
+ }
+\cs_new:Npn \@@_change_case_char:nnnnn #1#2#3#4#5
+ {
+ \int_compare:nNnTF {#1} = {#4}
+ { \tl_to_str:n {#5} }
+ {
+ \codepoint_str_generate:n {#1}
+ \tl_if_blank:nF {#2}
+ {
+ \codepoint_str_generate:n {#2}
+ \tl_if_blank:nF {#3}
+ { \codepoint_str_generate:n {#3} }
+ }
+ }
+ }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -2069,6 +2066,8 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
%
% \begin{variable}
% {
diff --git a/macros/latex/contrib/l3kernel/l3styleguide.pdf b/macros/latex/contrib/l3kernel/l3styleguide.pdf
index 4532b1ebeb..75ccd79ad8 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 20520ef462..b3578e3832 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 2022-11-02}
+\date{Released 2022-12-17}
\begin{document}
diff --git a/macros/latex/contrib/l3kernel/l3syntax-changes.pdf b/macros/latex/contrib/l3kernel/l3syntax-changes.pdf
index b7de97fd79..138dbc30cf 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 a5f009088b..1768810b84 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 2022-11-02}
+\date{Released 2022-12-17}
\newcommand{\TF}{\textit{(TF)}}
diff --git a/macros/latex/contrib/l3kernel/l3sys.dtx b/macros/latex/contrib/l3kernel/l3sys.dtx
index 6fa144c8a7..fa0bd971f7 100644
--- a/macros/latex/contrib/l3kernel/l3sys.dtx
+++ b/macros/latex/contrib/l3kernel/l3sys.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3term-glossary.pdf b/macros/latex/contrib/l3kernel/l3term-glossary.pdf
index daa7d1730c..d4c669ba6e 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 930982500d..25f41a2c18 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 2022-11-02}
+\date{Released 2022-12-17}
\newcommand{\TF}{\textit{(TF)}}
@@ -41,7 +41,7 @@ The released version of this bundle is available from CTAN.
\maketitle
This file describes aspects of \TeX{} programming that are relevant in a
-\LaTeX3 context.
+\pkg{expl3} context.
\section{Reading a file}
@@ -79,7 +79,7 @@ The meaning of a (non-active) character token is fixed by its category
code (and character code) and cannot be changed. We call these tokens
\emph{explicit} character tokens. Category codes that a character token
can have are listed below by giving a sample output of the \TeX{}
-primitive \tn{meaning}, together with their \LaTeX3 names and most
+primitive \tn{meaning}, together with their \pkg{expl3} names and most
common example:
\begin{itemize}
\item[1] begin-group character (|group_begin|, often |{|),
@@ -103,11 +103,11 @@ to that of any character token listed above (with any character code),
and we call such tokens \emph{implicit} character tokens. The meaning
is otherwise in the following list:
\begin{itemize}
- \item a macro, used in \LaTeX3 for most functions and some variables
+ \item a macro, used in \pkg{expl3} for most functions and some variables
(|tl|, |fp|, |seq|, \ldots{}),
- \item a primitive such as \tn{def} or \tn{topmark}, used in \LaTeX3
+ \item a primitive such as \tn{def} or \tn{topmark}, used in \pkg{expl3}
for some functions,
- \item a register such as \tn{count}|123|, used in \LaTeX3{} for the
+ \item a register such as \tn{count}|123|, used in \pkg{expl3} for the
implementation of some variables (|int|, |dim|, \ldots{}),
\item a constant integer such as \tn{char}|"56| or
\tn{mathchar}|"121|, used when defining a constant using
@@ -116,7 +116,7 @@ is otherwise in the following list:
\item undefined.
\end{itemize}
Macros can be \tn{protected} or not, \tn{long} or not (the opposite of
-what \LaTeX3 calls |nopar|), and \tn{outer} or not (unused in \LaTeX3).
+what \pkg{expl3} calls |nopar|), and \tn{outer} or not (unused in \pkg{expl3}).
Their \tn{meaning} takes the form
\begin{quote}
\meta{prefix} |macro:|\meta{argument}|->|\meta{replacement}
@@ -146,14 +146,4 @@ removed) becomes the argument. Note that explicit space characters at
the start of the argument are \emph{not} ignored in this case (and they
prevent brace-stripping).
-\section{Quantities and expressions}
-
-Integer denotations, dimensions, glue (including \texttt{fill} and \texttt{true pt} and the like).
-
-Syntax of integer expressions (including the trap that \verb|-(1+2)| is invalid).
-
-\section{\LaTeX3 terms}
-
-Terms like ``intexpr'' or ``seq var'' used in syntax blocks.
-
\end{document}
diff --git a/macros/latex/contrib/l3kernel/l3text-case.dtx b/macros/latex/contrib/l3kernel/l3text-case.dtx
index caaf003bcb..1767bc97e1 100644
--- a/macros/latex/contrib/l3kernel/l3text-case.dtx
+++ b/macros/latex/contrib/l3kernel/l3text-case.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -138,7 +138,8 @@
% \@@_change_case_group_titleonly:nnn
% }
% \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: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}
@@ -170,36 +171,38 @@
% }
% \begin{macro}[EXP]{\@@_change_case_letterlike:nnnnN}
% \begin{macro}[EXP]
-% {\@@_change_case_char_lower:nnN, \@@_change_case_char_upper:nnN}
+% {
+% \@@_change_case_codepoint_lower:nnn ,
+% \@@_change_case_codepoint_upper:nnn ,
+% \@@_change_case_codepoint_title:nnn ,
+% \@@_change_case_codepoint_titleonly:nnn
+% }
+% \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_lower_sigma:nnNw}
-% \begin{macro}[EXP]{\@@_change_case_lower_sigma:NnnN}
-% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnnNN}
-% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnw}
-% \begin{macro}[EXP]{\@@_change_case_lower_sigma:nnN}
% \begin{macro}[EXP]
-% {\@@_change_case_char_title:nnN, \@@_change_case_char_titleonly:nnN}
+% {
+% \@@_change_case_codepoint_title:nn ,
+% \@@_change_case_codepoint_titleonly:nn
+% }
+% \begin{macro}[EXP]{\@@_change_case_codepoint_title:nnnn}
% \begin{macro}[EXP]
-% {\@@_change_case_char_title:nN, \@@_change_case_char_titleonly:nN}
-% \begin{macro}[EXP]{\@@_change_case_char_title:nnnN}
+% {\@@_change_case_codepoint:nnnn, \@@_change_case_codepoint_aux:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_codepoint:nn}
% \begin{macro}[EXP]
% {
-% \@@_change_case_char:nnnN ,
-% \@@_change_case_char_auxi:nnnN ,
-% \@@_change_case_char_auxii:nnnN
+% \@@_change_case_codepoint:nnn ,
+% \@@_change_case_codepoint:fnn ,
+% \@@_change_case_codepoint_aux:nnn
% }
-% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nnnNN}
-% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nnnNNN}
-% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nnnNNNN}
-% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nnnn}
% \begin{macro}[EXP]
% {
-% \@@_change_case_char_next_lower:nn ,
-% \@@_change_case_char_next_upper:nn ,
-% \@@_change_case_char_next_title:nn ,
-% \@@_change_case_char_next_titleonly:nn
+% \@@_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
% }
-% \begin{macro}[EXP]{\@@_change_case_char_next_end:nn}
% 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
% (so the loops here don't need to worry about awkward look-aheads and the
@@ -246,7 +249,7 @@
{ \@@_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
{
- \cs_if_exist:cTF { @@_change_case_ #2 _ #5 -x- #3 :nnnN }
+ \cs_if_exist:cTF { @@_change_case_ #2 _ #5 -x- #3 :nnnn }
{ \@@_change_case_auxii:nnn {#1} {#2} { #5 -x- #3 } }
{ \@@_change_case_auxii:nnn {#1} {#2} {#4} }
}
@@ -429,9 +432,12 @@
\cs_new:Npn \@@_change_case_cs_check:nnN #1#2#3
{
\token_if_cs:NTF #3
- { \@@_change_case_exclude:nnN }
- { \use:c { @@_change_case_char_ #1 :nnN } }
- {#1} {#2} #3
+ { \@@_change_case_exclude:nnN {#1} {#2} }
+ {
+ \@@_codepoint_process:nN
+ { \use:c { @@_change_case_codepoint_ #1 :nnn } {#1} {#2} }
+ }
+ #3
}
% \end{macrocode}
% To deal with a control sequence there is first a need to test if it is
@@ -545,7 +551,7 @@
{
\@@_change_case_store:v
{ c_@@_ #1 case_ \token_to_str:N #5 _tl }
- \use:c { @@_change_case_char_next_ #2 :nn } {#2} {#4}
+ \use:c { @@_change_case_next_ #2 :nn } {#2} {#4}
}
{
\@@_change_case_store:n {#5}
@@ -555,7 +561,7 @@
\str_if_eq:nnTF {#1} { lower } { upper } { lower }
case_ \token_to_str:N #5 _tl
}
- { \use:c { @@_change_case_char_next_ #2 :nn } {#2} {#4} }
+ { \use:c { @@_change_case_next_ #2 :nn } {#2} {#4} }
{ \@@_change_case_loop:nnw {#3} {#4} }
}
}
@@ -563,222 +569,196 @@
% For upper- and lowercase changes, once we get to this stage there are only
% a couple of questions remaining: is there a language-specific mapping and
% is there the special case of a terminal sigma. If not, then we pass to
-% a simple character mapping.
+% a simple codepoint mapping.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_char_lower:nnN #1#2#3
+\cs_new:Npn \@@_change_case_codepoint_lower:nnn #1#2#3
{
- \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_ #2 :nnnn }
+ { \@@_change_case_lower_sigma:nnnn }
+ {#1} {#1} {#2} {#3}
}
-\cs_new:Npn \@@_change_case_char_upper:nnN #1#2#3
+\cs_new:Npn \@@_change_case_codepoint_upper:nnn #1#2#3
{
- \cs_if_exist_use:cF { @@_change_case_upper_ #2 :nnnN }
- { \@@_change_case_char:nnnN }
- {#1} {#1} {#2} #3
+ \cs_if_exist_use:cF { @@_change_case_upper_ #2 :nnnn }
+ { \@@_change_case_codepoint:nnnn }
+ {#1} {#1} {#2} {#3}
}
% \end{macrocode}
% If the current character is an uppercase sigma, the a check is made on the
% next item in the input. If it is \texttt{N}-type and not a control sequence
-% then there is a look-ahead phase: the logic here is simply based on letters.
-% The one exception is Dutch: see below.
+% then there is a look-ahead phase: the logic here is simply based on letters
+% or actives (to cover $8$-bit engines).
% \begin{macrocode}
-\bool_lazy_or:nnTF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
+\cs_new:Npn \@@_change_case_lower_sigma:nnnn #1#2#3#4
{
- \cs_new:Npn \@@_change_case_lower_sigma:nnnN #1#2#3#4
- {
- \int_compare:nNnTF { `#4 } = { "03A3 }
- { \@@_change_case_lower_sigma:nnNw {#2} {#3} #4 }
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
- }
- \cs_new:Npn \@@_change_case_lower_sigma:nnNw #1#2#3#4 \q_@@_recursion_stop
- {
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_lower_sigma:NnnN #3 }
- {
- \@@_change_case_store:e
- { \char_generate:nn { "03C2 } { \@@_char_catcode:N #3 } }
- \@@_change_case_loop:nnw
- }
- {#1} {#2} #4 \q_@@_recursion_stop
- }
- \cs_new:Npn \@@_change_case_lower_sigma:NnnN #1#2#3#4
+ \@@_codepoint_compare:nNnTF {#4} = { "03A3 }
+ { \@@_change_case_lower_sigma:nnnw {#2} }
+ { \@@_change_case_codepoint:nnnn {#1} {#2} }
+ {#3} {#4}
+ }
+\cs_new:Npn \@@_change_case_lower_sigma:nnnw #1#2#3#4 \q_@@_recursion_stop
+ {
+ \tl_if_head_is_N_type:nTF {#4}
+ { \@@_change_case_lower_sigma:nnnN {#3} }
{
\@@_change_case_store:e
- {
- \token_if_letter:NTF #4
- { \char_generate:nn { "03C3 } { \@@_char_catcode:N #1 } }
- { \char_generate:nn { "03C2 } { \@@_char_catcode:N #1 } }
- }
- \@@_change_case_loop:nnw {#2} {#3} #4
+ { \codepoint_generate:nn { "03C2 } { \@@_char_catcode:N #3 } }
+ \@@_change_case_loop:nnw
}
+ {#1} {#2} #4 \q_@@_recursion_stop
}
-% \end{macrocode}
-% In the $8$-bit engines, we have to look ahead once we find the first byte of the
-% possible hit.
-% \begin{macrocode}
+\cs_new:Npn \@@_change_case_lower_sigma:nnnN #1#2#3#4
{
- \cs_new:Npn \@@_change_case_lower_sigma:nnnN #1#2#3#4
- {
- \int_compare:nNnTF { `#4 } = { "CE }
- { \@@_change_case_lower_sigma:nnnNN }
- { \@@_change_case_char:nnnN }
- {#1} {#2} {#3} #4
- }
- \cs_new:Npn \@@_change_case_lower_sigma:nnnNN #1#2#3#4#5
- {
- \int_compare:nNnTF { `#5 } = { "A3 }
- { \@@_change_case_lower_sigma:nnw {#2} {#3} }
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4#5 }
- }
- \cs_new:Npn \@@_change_case_lower_sigma:nnw #1#2#3 \q_@@_recursion_stop
- {
- \tl_if_head_is_N_type:nTF {#3}
- { \@@_change_case_lower_sigma:nnN }
- {
- \@@_change_case_store:V \c_@@_final_sigma_tl
- \@@_change_case_loop:nnw
- }
- {#1} {#2} #3 \q_@@_recursion_stop
- }
- \cs_new:Npn \@@_change_case_lower_sigma:nnN #1#2#3
+ \@@_change_case_store:e
{
\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 } }
}
- { \@@_change_case_store:V \c_@@_sigma_tl }
- { \@@_change_case_store:V \c_@@_final_sigma_tl }
- \@@_change_case_loop:nnw {#1} {#2} #3
+ { \codepoint_generate:nn { "03C3 } { \@@_char_catcode:N #1 } }
+ { \codepoint_generate:nn { "03C2 } { \@@_char_catcode:N #1 } }
}
+ \@@_change_case_loop:nnw {#2} {#3} #4
}
% \end{macrocode}
% For titlecasing, we need to fully expand the new character to see if it
-% is a letter (or active) But that means looking ahead in the $8$-bit case, so
-% we have to grab the required tokens up-front. Life is a lot easier for Unicode
-% \TeX{}'s, where we just have one token to worry about. The one wrinkle here
-% is that for look-ahead we'd get into trouble: luckily, only Dutch has that
-% issue.
+% is a letter (or active).
% \begin{macrocode}
-\cs_new:Npx \@@_change_case_char_title:nnN #1#2#3
+\cs_new:Npn \@@_change_case_codepoint_title:nnn #1#2#3
{
- \exp_not:N \bool_if:NTF \l_text_titlecase_check_letter_bool
+ \bool_if:NTF \l_text_titlecase_check_letter_bool
{
- \bool_lazy_or:nnTF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
- { \exp_not:N \token_if_letter:NTF #3 }
+ \tl_if_single:nTF {#3}
{
- \exp_not:N \bool_lazy_or:nnTF
- { \exp_not:N \token_if_letter_p:N #3 }
- { \exp_not:N \token_if_active_p:N #3 }
+ \bool_lazy_or:nnTF
+ { \token_if_letter_p:N #3 }
+ {
+ \bool_lazy_and_p:nn
+ { \token_if_active_p:N #3 }
+ { ! \int_compare_p:nNn {`#3} < { "80 } }
+ }
+ { \use:c { @@_change_case_codepoint_ #1 :nn } }
+ { \@@_change_case_codepoint_title:nnnn { title } {#1} }
}
- { \exp_not:N \use:c { @@_change_case_char_ #1 :nN } }
- { \exp_not:N \@@_change_case_char_title:nnnN { title } {#1} }
+ { \use:c { @@_change_case_codepoint_ #1 :nn } }
}
- { \exp_not:N \use:c { @@_change_case_char_ #1 :nN } }
- {#2} #3
+ { \use:c { @@_change_case_codepoint_ #1 :nn } }
+ {#2} {#3}
}
-\cs_new_eq:NN \@@_change_case_char_titleonly:nnN
- \@@_change_case_char_title:nnN
-\cs_new:Npn \@@_change_case_char_title:nN #1#2
- { \@@_change_case_char_title:nnnN { title } { lower } {#1} #2 }
-\cs_new:Npn \@@_change_case_char_titleonly:nN #1#2
- { \@@_change_case_char_title:nnnN { title } { end } {#1} #2 }
-\cs_new:Npn \@@_change_case_char_title:nnnN #1#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_if_exist_use:cF { @@_change_case_title_ #3 :nnnN }
+ \cs_if_exist_use:cF { @@_change_case_title_ #3 :nnnn }
{
- \cs_if_exist_use:cF { @@_change_case_upper_ #3 :nnnN }
- { \@@_change_case_char:nnnN }
+ \cs_if_exist_use:cF { @@_change_case_upper_ #3 :nnnn }
+ { \@@_change_case_codepoint:nnnn }
}
- {#1} {#2} {#3} #4
+ {#1} {#2} {#3} {#4}
}
-% \end{macrocode}
-% For Unicode engines we can handle all characters directly. However, for
-% the $8$-bit engines the aim is to deal with (a subset of) Unicode (UTF-8)
-% input. They deal with that by making the upper half of the range active,
-% so we look for that and if found work out how many UTF-8 octets there
-% are to deal with. Those can then be grabbed to reconstruct the full
-% Unicode character, which is then used in a lookup. (As will become
-% obvious below, there is no intention here of covering all of Unicode.)
-% For (u)p-\TeX{} there are a limited number of tokens we can touch.
-% \begin{macrocode}
-\cs_new:Npn \@@_change_case_char:nnnN #1#2#3#4
+\cs_new:Npn \@@_change_case_codepoint:nnnn #1#2#3#4
{
- \token_if_active:NTF #4
+ \bool_lazy_and:nnTF
+ { \tl_if_single_p:n {#4} }
+ { \token_if_active_p:N #4 }
{ \@@_change_case_store:n {#4} }
{
\@@_change_case_store:e
- { \use:c { char_ #1 case :N } #4 }
+ { \@@_change_case_codepoint:nn {#1} {#4} }
}
- \use:c { @@_change_case_char_next_ #2 :nn } {#2} {#3}
+ \use:c { @@_change_case_next_ #2 :nn } {#2} {#3}
}
-\bool_lazy_or:nnF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
+\cs_new:Npn \@@_change_case_codepoint:nn #1#2
{
- \cs_new_eq:NN \@@_change_case_char_auxi:nnnN
- \@@_change_case_char:nnnN
- \cs_gset:Npn \@@_change_case_char:nnnN #1#2#3#4
- {
- \int_compare:nNnTF { `#4 } > { "80 }
- {
- \int_compare:nNnTF { `#4 } < { "E0 }
- { \@@_change_case_char_UTFviii:nnnNN }
- { \@@_change_case_char_auxii:nnnN }
- }
- { \@@_change_case_char_auxi:nnnN }
- {#1} {#2} {#3} #4
- }
- \sys_if_engine_pdftex:TF
+ \@@_change_case_codepoint:fnn
+ { \int_eval:n { \@@_codepoint_from_chars:Nw #2 } } {#1} {#2}
+ }
+\cs_new:Npn \@@_change_case_codepoint:nnn #1#2#3
+ {
+ \exp_args:Ne \@@_change_case_codepoint_aux:nn
+ { \__kernel_codepoint_case:nn { #2 case } {#1} } {#3}
+ }
+\cs_generate_variant:Nn \@@_change_case_codepoint:nnn { f }
+% \end{macrocode}
+% Avoid high chars with p\TeX{}.
+% \begin{macrocode}
+\sys_if_engine_ptex:T
+ {
+ \cs_new_eq:NN \@@_change_case_codepoint_aux:nnn
+ \@@_change_case_codepoint:nnn
+ \cs_gset:Npn \@@_change_case_codepoint:nnn #1#2#3
{
- \cs_new:Npn \@@_change_case_char_auxii:nnnN #1#2#3#4
- {
- \int_compare:nNnTF { `#4 } < { "F0 }
- { \@@_change_case_char_UTFviii:nnnNNN }
- { \@@_change_case_char_UTFviii:nnnNNNN }
- {#1} {#2} {#3} #4
- }
+ \int_compare:nNnTF {#1} = { -1 }
+ { \exp_not:n {#3} }
+ { \@@_change_case_codepoint_aux:nnn {#1} {#2} {#3} }
}
+ }
+\cs_new:Npn \@@_change_case_codepoint_aux:nn #1#2
+ {
+ \use:e { \@@_change_case_codepoint_aux:nnnn #1 {#2} }
+ }
+\cs_new:Npn \@@_change_case_codepoint_aux:nnnn #1#2#3#4
+ {
+ \@@_codepoint_compare:nNnTF {#4} = {#1}
+ { \exp_not:n {#4} }
{
- \cs_new:Npn \@@_change_case_char_auxii:nnnN #1#2#3#4
+ \codepoint_generate:nn {#1}
+ { \@@_change_case_catcode:nn {#4} {#1} }
+ \tl_if_blank:nF {#2}
{
- \@@_change_case_store:n {#4}
- \use:c { @@_change_case_char_next_ #2 :nn } {#2} {#3}
+ \codepoint_generate:nn {#2}
+ { \char_value_catcode:n {#2} }
+ \tl_if_blank:nF {#3}
+ {
+ \codepoint_generate:nn {#3}
+ { \char_value_catcode:n {#3} }
+ }
}
}
- \cs_new:Npn \@@_change_case_char_UTFviii:nnnNN #1#2#3#4#5
- { \@@_change_case_char_UTFviii:nnnn {#1} {#2} {#3} {#4#5} }
- \cs_new:Npn \@@_change_case_char_UTFviii:nnnNNN #1#2#3#4#5#6
- { \@@_change_case_char_UTFviii:nnnn {#1} {#2} {#3} {#4#5#6} }
- \cs_new:Npn \@@_change_case_char_UTFviii:nnnNNNN #1#2#3#4#5#6#7
- { \@@_change_case_char_UTFviii:nnnn {#1} {#2} {#3} {#4#5#6#7} }
- \cs_new:Npn \@@_change_case_char_UTFviii:nnnn #1#2#3#4
+ }
+% \end{macrocode}
+% We need to ensure that only valid catcode-extraction is attempted. That's
+% fine with Unicode engines but needs a bit of work with 8-bit ones. The
+% logic is that if the original codepoint was in the ASCII range, we keep
+% the catcode. Otherwise, if the target is in the ASCII range, we use
+% the standard catcode. If neither are true, we set as 13 on the grounds that
+% this will be what is used anyway!
+% \begin{macrocode}
+\bool_lazy_or:nnTF
+ { \sys_if_engine_luatex_p: }
+ { \sys_if_engine_xetex_p: }
+ {
+ \cs_new:Npn \@@_change_case_catcode:nn #1#2
+ { \@@_char_catcode:N #1 }
+ }
+ {
+ \cs_new:Npn \@@_change_case_catcode:nn #1#2
{
- \cs_if_exist:cTF { c__kernel_ #1 case_ \tl_to_str:n {#4} _tl }
+ \@@_codepoint_compare:nNnTF {#1} < { "80 }
+ { \@@_char_catcode:N #1 }
{
- \@@_change_case_store:v
- { c__kernel_ #1 case_ \tl_to_str:n {#4} _tl }
+ \int_compare:nNnTF {#2} < { "80 }
+ { \char_value_catcode:n {#2} }
+ { 13 }
}
- { \@@_change_case_store:n {#4} }
- \use:c { @@_change_case_char_next_ #2 :nn } {#2} {#3}
}
}
-\cs_new:Npn \@@_change_case_char_next_lower:nn #1#2
+\cs_new:Npn \@@_change_case_next_lower:nn #1#2
{ \@@_change_case_loop:nnw {#1} {#2} }
-\cs_new_eq:NN \@@_change_case_char_next_upper:nn
- \@@_change_case_char_next_lower:nn
-\cs_new_eq:NN \@@_change_case_char_next_title:nn
- \@@_change_case_char_next_lower:nn
-\cs_new_eq:NN \@@_change_case_char_next_titleonly:nn
- \@@_change_case_char_next_lower:nn
-\cs_new:Npn \@@_change_case_char_next_end:nn #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 }
% \end{macrocode}
% \end{macro}
@@ -822,13 +802,6 @@
% \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.
@@ -855,76 +828,63 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_change_case_upper_de-x-eszett:nnnN, \@@_change_case_upper_de-alt:nnnN}
-% \begin{macro}[EXP]{\@@_change_case_upper_de-x-eszett:nnnNN}
+% \begin{macro}[EXP]
+% {\@@_change_case_upper_de-x-eszett:nnnn, \@@_change_case_upper_de-alt:nnnn}
% A simple alternative version for German.
% \begin{macrocode}
-\bool_lazy_or:nnTF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
- {
- \cs_new:cpn { @@_change_case_upper_de-x-eszett:nnnN } #1#2#3#4
- {
- \int_compare:nNnTF { `#4 } = { "00DF }
- {
- \@@_change_case_store:e
- { \char_generate:nn { "1E9E } { \@@_char_catcode:N #4 } }
- \use:c { @@_change_case_char_next_ #2 :nn }
- {#2} {#3}
- }
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
- }
- }
+\cs_new:cpn { @@_change_case_upper_de-x-eszett:nnnn } #1#2#3#4
{
- \cs_new:cpx { @@_change_case_upper_de-x-eszett:nnnN } #1#2#3#4
+ \@@_codepoint_compare:nNnTF {#4} = { "00DF }
{
- \exp_not:N \int_compare:nNnTF { `#4 } = { "00C3 }
- {
- \exp_not:c { @@_change_case_upper_de-x-eszett:nnnNN }
- {#1} {#2} {#3} #4
- }
- { \exp_not:N \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
- }
- \cs_new:cpn { @@_change_case_upper_de-x-eszett:nnnNN } #1#2#3#4#5
- {
- \int_compare:nNnTF { `#5 } = { "009F }
- {
- \@@_change_case_store:V \c_@@_grosses_Eszett_tl
- \use:c { @@_change_case_char_next_ #2 :nn } {#2} {#3}
- }
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4#5 }
+ \@@_change_case_store:e
+ {
+ \codepoint_generate:nn { "1E9E }
+ { \@@_change_case_catcode:nn {#4} { "1E9E } }
+ }
+ \use:c { @@_change_case_next_ #2 :nn }
+ {#2} {#3}
}
+ { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
}
-\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:nnnn }
+ { @@_change_case_upper_de-x-eszett:nnnn }
% \end{macrocode}
% \end{macro}
-% \end{macro}
%
% \begin{macro}[EXP]
-% {\@@_change_case_upper_el:nnnN, \@@_change_case_upper_el-x-iota:nnnN}
+% {
+% \@@_change_case_upper_el:nnnn ,
+% \@@_change_case_upper_el_aux:nnnn ,
+% \@@_change_case_upper_el-x-iota:nnnn
+% }
% \begin{macro}[EXP]
-% {\@@_change_case_upper_el:N, \@@_change_case_upper_el-x-iota:N}
+% {\@@_change_case_upper_el:n, \@@_change_case_upper_el-x-iota:n}
% \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_ypogegrammeni:Nnnnnw}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_ypogegrammeni:NnnnnN}
-% \begin{macro}[EXP]{\@@_change_case_upper_el_dialytika:nnN}
-% \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:nnnw}
+% \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}
+% \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:nnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_hiatus:nnn}
% \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:nnnNN}
-% \begin{macro}[EXP]{\@@_change_case_upper_el:nnnNNN}
-% \begin{macro}[EXP]{\@@_change_case_upper_el:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnn}
% \begin{macro}[EXP,TF]{\@@_change_case_if_greek:n}
+% \begin{macro}[EXP]{\@@_change_case_if_greek:n}
% \begin{macro}[EXP,pTF]{\@@_change_case_if_greek:n}
% \begin{macro}[EXP,pTF]{\@@_change_case_if_greek_accent:n}
+% \begin{macro}[EXP]{\@@_change_case_if_greek_accent:n}
% \begin{macro}[EXP,pTF]{\@@_change_case_if_greek_diacritic:n}
+% \begin{macro}[EXP]{\@@_change_case_if_greek_diacritic:n}
% \begin{macro}[EXP,TF]{\@@_change_case_if_takes_dialytika:n}
+% \begin{macro}[EXP]{\@@_change_case_if_takes_dialytika:n}
% \begin{macro}[EXP,TF]{\@@_change_case_if_takes_ypogegrammeni:n}
+% \begin{macro}[EXP]{\@@_change_case_if_takes_ypogegrammeni:n}
% For Greek uppercasing, we need to know if characters \emph{in the Greek
% range} have accents. That means doing a \textsc{nfd} conversion first, then
% starting a search. As described by the Unicode \textsc{cldr}, Greek accents
@@ -936,55 +896,58 @@
% \emph{ypogegrammeni} is filtered out here as it is not actually in the
% Greek range, so gets lost if we leave until later.
% \begin{macrocode}
-\bool_lazy_or:nnTF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
+\cs_new:Npn \@@_change_case_upper_el:nnnn #1#2#3#4
{
- \cs_new:Npn \@@_change_case_upper_el:nnnN #1#2#3#4
+ \@@_change_case_if_greek:nTF {#4}
{
- \@@_change_case_if_greek:nTF { `#4 }
+ \exp_args:Ne \@@_change_case_upper_el:nnn
{
- \exp_args:Ne \@@_change_case_upper_el:nnn
- { \char_to_nfd:N #4 } {#2} {#3}
+ \codepoint_to_nfd:n { \@@_codepoint_from_chars:Nw #4 }
}
+ {#2} {#3}
+ }
+ {
+ \@@_codepoint_compare:nNnTF {#4} = { "0345 }
{
- \int_compare:nNnTF { `#4 } = { "0345 }
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
- {
- \use:c { @@_change_case_upper_ #3 :N } #4
- }
- \@@_change_case_loop:nnw {#2} {#3}
+ \use:c { @@_change_case_upper_ #3 :n } {#4}
}
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+ \@@_change_case_loop:nnw {#2} {#3}
}
+ { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
}
- \cs_new_eq:cN { @@_change_case_upper_el-x-iota:nnnN }
- \@@_change_case_upper_el:nnnN
- \cs_new:Npn \@@_change_case_upper_el:N #1
- {
- \char_generate:nn { "0399 }
- { \char_value_catcode:n { "0399 } }
- }
- \cs_new:cpn { @@_change_case_upper_el-x-iota:N } #1
- { \exp_not:n {#1} }
- \cs_new:Npn \@@_change_case_upper_el:nnn #1#2#3
- { \@@_change_case_upper_el:nnNw {#2} {#3} #1 }
+ }
+\cs_new_eq:cN { @@_change_case_upper_el-x-iota:nnnn }
+ \@@_change_case_upper_el:nnnn
+\cs_new:Npn \@@_change_case_upper_el:n #1
+ {
+ \codepoint_generate:nn { "0399 }
+ { \char_value_catcode:n { "0399 } }
+ }
+\cs_new:cpn { @@_change_case_upper_el-x-iota:n } #1
+ { \exp_not:n {#1} }
+\cs_new:Npn \@@_change_case_upper_el:nnn #1#2#3
+ {
+ \@@_codepoint_process:nN
+ { \@@_change_case_upper_el:nnnw {#2} {#3} } #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 token, either from the NFD or
+% 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:nnnw #1#2#3#4 \q_@@_recursion_stop
+ {
+ \tl_if_head_is_N_type:nTF {#4}
+ { \@@_change_case_upper_el:nnnN {#3} }
{
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_upper_el:NnnN #3 }
- {
- \@@_change_case_store:e { \char_uppercase:N #3 }
- \@@_change_case_loop:nnw
- }
- {#1} {#2} #4 \q_@@_recursion_stop
+ \@@_change_case_store:e
+ { \@@_change_case_codepoint:nn { upper } {#3} }
+ \@@_change_case_loop:nnw
}
+ {#1} {#2} #4 \q_@@_recursion_stop
+ }
% \end{macrocode}
% Now, we check the detail of the next codepoint: again we filter out the
% not-a-char cases, before checking if it's an dialytika, accent or diacritic.
@@ -993,193 +956,200 @@
% 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:nnnN #1#2#3#4
+ {
+ \token_if_cs:NTF #4
{
- \token_if_cs:NTF #4
- {
- \@@_change_case_store:e { \char_uppercase:N #1 }
- \@@_change_case_loop:nnw {#2} {#3} #4
- }
+ \@@_change_case_store:e
+ { \@@_change_case_codepoint:nn { upper } {#1} }
+ \@@_change_case_loop:nnw {#2} {#3} #4
+ }
+ {
+ \@@_change_case_if_takes_ypogegrammeni:nTF {#1}
{
- \@@_change_case_if_takes_ypogegrammeni:nTF { `#1 }
- {
- \@@_change_case_upper_el_ypogegrammeni:Nnnnnw
- #1 {#2} {#3} { } { } #4
- }
- { \@@_change_case_upper_el_aux:NnnN #1 {#2} {#3} #4 }
+ \@@_change_case_upper_el_ypogegrammeni:nnnnnw
+ {#1} {#2} {#3} { } { } #4
}
+ { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4 }
}
- \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:nnnnnw
+ #1#2#3#4#5#6 \q_@@_recursion_stop
+ {
+ \tl_if_head_is_N_type:nTF {#6}
{
- \tl_if_head_is_N_type:nTF {#6}
+ \@@_change_case_upper_el_ypogegrammeni:nnnnnN
+ {#1} {#2} {#3} {#4} {#5}
+ }
+ { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4#5 }
+ #6 \q_@@_recursion_stop
+ }
+\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnN #1#2#3#4#5#6
+ {
+ \token_if_cs:NTF #6
+ { \@@_change_case_upper_el_aux:nnnN {#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:nnnnnn
+ {#1} {#2} {#3} {#4} {#5}
}
- { \@@_change_case_upper_el_aux:NnnN #1 {#2} {#3} #4#5 }
- #6 \q_@@_recursion_stop
+ #6
+ }
+ }
+\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_codepoint_compare:nNnTF {#6} = { "0345 }
+ {
+ \@@_change_case_upper_el_ypogegrammeni:nnnnnw
+ {#1} {#2} {#3} {#4} {#6}
}
- \cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:NnnnnN #1#2#3#4#5#6
{
- \token_if_cs:NTF #6
- { \@@_change_case_upper_el_aux:NnnN #1 {#2} {#3} #4#5 #6 }
+ \bool_lazy_or:nnTF
+ { \@@_change_case_if_greek_accent_p:n {#6} }
+ { \@@_change_case_if_greek_diacritic_p:n {#6} }
{
- \int_compare:nNnTF { `#6 } = { "0345 }
- {
- \@@_change_case_upper_el_ypogegrammeni:Nnnnnw
- #1 {#2} {#3} {#4} {#6}
- }
- {
- \bool_lazy_or:nnTF
- { \@@_change_case_if_greek_accent_p:n { `#6 } }
- { \@@_change_case_if_greek_diacritic_p:n { `#6 } }
- {
- \@@_change_case_upper_el_ypogegrammeni:Nnnnnw
- #1 {#2} {#3} {#4#6} {#5}
- }
- { \@@_change_case_upper_el_aux:NnnN #1 {#2} {#3} #4#5 #6 }
- }
+ \@@_change_case_upper_el_ypogegrammeni:nnnnnw
+ {#1} {#2} {#3} {#4#6} {#5}
}
+ { \@@_change_case_upper_el_aux:nnnN {#1} {#2} {#3} #4#5 #6 }
}
- \cs_new:Npn \@@_change_case_upper_el_aux:NnnN #1#2#3#4
+ }
+\cs_new:Npn \@@_change_case_upper_el_aux:nnnN #1#2#3#4
+ {
+ \@@_codepoint_process:nN
+ { \@@_change_case_upper_el_aux:nnnn {#1} {#2} {#3} } #4
+ }
+\cs_new:Npn \@@_change_case_upper_el_aux:nnnn #1#2#3#4
+ {
+ \@@_codepoint_compare:nNnTF {#4} = { "0308 }
+ { \@@_change_case_upper_el_dialytika:nnn {#2} {#3} {#1} }
{
- \int_compare:nNnTF { `#4 } = { "0308 }
- { \@@_change_case_upper_el_dialytika:nnN {#2} {#3} #1 }
+ \@@_change_case_if_greek_accent:nTF {#4}
+ { \@@_change_case_upper_el_hiatus:nnnw {#2} {#3} {#1} }
{
- \@@_change_case_if_greek_accent:nTF { `#4 }
- { \@@_change_case_upper_el_hiatus:nnNw {#2} {#3} #1 }
+ \@@_change_case_if_greek_diacritic:nTF {#4}
{
- \@@_change_case_if_greek_diacritic:nTF { `#4 }
- {
- \@@_change_case_store:e { \char_uppercase:N #1 }
- \@@_change_case_loop:nnw {#2} {#3}
- }
+ \@@_change_case_store:e
+ { \@@_change_case_codepoint:nn { upper } {#1} }
+ \@@_change_case_loop:nnw {#2} {#3}
+ }
+ {
+ \@@_codepoint_compare:nNnTF {#4} = { "0345 }
+ { \@@_change_case_store:e { [XXX] } }
{
- \int_compare:nNnTF { `#4 } = { "0345 }
- { \@@_change_case_store:e { [XXX] } }
- { \@@_change_case_store:e { \char_uppercase:N #1 } }
- \@@_change_case_loop:nnw {#2} {#3} #4
+ \@@_change_case_store:e
+ { \@@_change_case_codepoint:nn { upper } {#1} }
}
+ \@@_change_case_loop:nnw {#2} {#3} #4
}
}
}
-% \end{macrocode}
+ }
+% \end{macrocode}
% We handle \emph{dialytika} in parts as it's also needed for the hiatus.
% 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:nnn #1#2#3
+ {
+ \@@_change_case_if_takes_dialytika:nTF {#3}
+ { \@@_change_case_upper_el_dialytika:n {#3} }
{
- \@@_change_case_if_takes_dialytika:nTF { `#3 }
- { \@@_change_case_upper_el_dialytika:N #3 }
- { \@@_change_case_store:e { \char_uppercase:N #3 } }
- \@@_change_case_upper_el_gobble:nnw {#1} {#2}
+ \@@_change_case_store:e
+ { \@@_change_case_codepoint:nn { upper } {#3} }
}
- \cs_new:Npn \@@_change_case_upper_el_dialytika:N #1
+ \@@_change_case_upper_el_gobble:nnw {#1} {#2}
+ }
+\cs_new:Npn \@@_change_case_upper_el_dialytika:n #1
+ {
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
+ \bool_lazy_or:nnTF
+ { \@@_codepoint_compare_p:nNn {#1} = { "0399 } }
+ { \@@_codepoint_compare_p:nNn {#1} = { "03B9 } }
{
- \bool_lazy_or:nnTF
- { \int_compare_p:nNn { `#1 } = { "0399 } }
- { \int_compare_p:nNn { `#1 } = { "03B9 } }
- { \char_generate:nn { "03AA } { \@@_char_catcode:N #1 } }
- { \char_generate:nn { "03AB } { \@@_char_catcode:N #1 } }
+ \codepoint_generate:nn { "03AA }
+ { \@@_change_case_catcode:nn {#1} { "03AA } }
+ }
+ {
+ \codepoint_generate:nn { "03AB }
+ { \@@_change_case_catcode:nn {#1} { "03AB } }
}
}
+ }
% \end{macrocode}
% 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:nnnw
+ #1#2#3#4 \q_@@_recursion_stop
+ {
+ \@@_change_case_store:e
+ { \@@_change_case_codepoint:nn { upper } {#3} }
+ \tl_if_head_is_N_type:nTF {#4}
+ { \@@_change_case_upper_el_hiatus:nnN }
+ { \@@_change_case_loop:nnw }
+ {#1} {#2} #4 \q_@@_recursion_stop
+ }
+\cs_new:Npn \@@_change_case_upper_el_hiatus:nnN #1#2#3
+ {
+ \token_if_cs:NTF #3
+ { \@@_change_case_loop:nnw {#1} {#2} #3 }
{
- \@@_change_case_store:e { \char_uppercase:N #3 }
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_upper_el_hiatus:nnN }
- { \@@_change_case_loop:nnw }
- {#1} {#2} #4 \q_@@_recursion_stop
+ \@@_codepoint_process:nN
+ { \@@_change_case_upper_el_hiatus:nnn {#1} {#2} } #3
}
- \cs_new:Npn \@@_change_case_upper_el_hiatus:nnN #1#2#3
+ }
+\cs_new:Npn \@@_change_case_upper_el_hiatus:nnn #1#2#3
+ {
+ \@@_change_case_if_takes_dialytika:nTF {#3}
{
- \token_if_cs:NTF #3
- { \@@_change_case_loop:nnw {#1} {#2} #3 }
- {
- \@@_change_case_if_takes_dialytika:nTF { `#3 }
- {
- \@@_change_case_upper_el_dialytika:N #3
- \@@_change_case_upper_el_gobble:nnw {#1} {#2}
- }
- { \@@_change_case_loop:nnw {#1} {#2} #3 }
- }
+ \@@_change_case_upper_el_dialytika:n {#3}
+ \@@_change_case_upper_el_gobble:nnw {#1} {#2}
}
+ { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ }
% \end{macrocode}
% 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
- {
- \tl_if_head_is_N_type:nTF {#3}
- { \@@_change_case_upper_el_gobble:nnN }
- { \@@_change_case_loop:nnw }
- {#1} {#2} #3 \q_@@_recursion_stop
- }
- \cs_new:Npn \@@_change_case_upper_el_gobble:nnN #1#2#3
- {
- \bool_lazy_or:nnTF
- { \token_if_cs_p:N #3 }
- {
- ! \bool_lazy_or_p:nn
- { \@@_change_case_if_greek_accent_p:n { `#3 } }
- { \@@_change_case_if_greek_diacritic_p:n { `#3 } }
- }
- { \@@_change_case_loop:nnw {#1} {#2} #3 }
- { \@@_change_case_upper_el_gobble:nnw {#1} {#2} }
- }
+\cs_new:Npn \@@_change_case_upper_el_gobble:nnw
+ #1#2#3 \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
}
-% \end{macrocode}
-% For $8$-bit engines we use a simplified approach: covers the common
-% requirements. This is basically how \pkg{xgreek} works but done by
-% expansion: use fixed mappings from accented to accent-free letters.
-% Only the two- and three-byte ranges can be involved.
-% \begin{macrocode}
+\cs_new:Npn \@@_change_case_upper_el_gobble:nnN #1#2#3
{
- \cs_new:Npn \@@_change_case_upper_el:nnnN #1#2#3#4
- {
- \int_compare:nNnTF { `#4 } > { "80 }
- {
- \int_compare:nNnTF { `#4 } < { "E0 }
- { \@@_change_case_upper_el:nnnNN }
- {
- \int_compare:nNnTF { `#4 } < { "F0 }
- { \@@_change_case_upper_el:nnnNNN }
- { \@@_change_case_char:nnnN }
- }
- }
- { \@@_change_case_char:nnnN }
- {#1} {#2} {#3} #4
- }
- \cs_new:Npn \@@_change_case_upper_el:nnnNN #1#2#3#4#5
- { \@@_change_case_upper_el:nnnn {#1} {#2} {#3} {#4#5} }
- \cs_new:Npn \@@_change_case_upper_el:nnnNNN #1#2#3#4#5#6
- { \@@_change_case_upper_el:nnnn {#1} {#2} {#3} {#4#5#6} }
- \cs_new:Npn \@@_change_case_upper_el:nnnn #1#2#3#4
+ \token_if_cs:NTF #3
+ { \@@_change_case_loop:nnw {#1} {#2} }
{
- \cs_if_exist:cTF { c_@@_uppercase_el_ \tl_to_str:n {#4} _tl }
- {
- \@@_change_case_store:v
- { c_@@_uppercase_el_ \tl_to_str:n {#4} _tl }
- \@@_change_case_loop:nnw {#1} {#3}
- }
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+ \@@_codepoint_process:nN
+ { \@@_change_case_upper_el_gobble:nnn {#1} {#2} }
}
+ #3
+ }
+\cs_new:Npn \@@_change_case_upper_el_gobble:nnn #1#2#3
+ {
+ \bool_lazy_or:nnTF
+ { \@@_change_case_if_greek_accent_p:n {#3} }
+ { \@@_change_case_if_greek_diacritic_p:n {#3} }
+ { \@@_change_case_upper_el_gobble:nnw {#1} {#2} }
+ { \@@_change_case_loop:nnw {#1} {#2} #3 }
}
% \end{macrocode}
% Luckily the Greek range is limited and clear.
% \begin{macrocode}
\prg_new_conditional:Npnn \@@_change_case_if_greek:n #1 { TF }
{
+ \exp_args:Nf \@@_change_case_if_greek:n
+ { \int_eval:n { \@@_codepoint_from_chars:Nw #1 } }
+ }
+\cs_new:Npn \@@_change_case_if_greek:n #1
+ {
\if_int_compare:w #1 < "0370 \exp_stop_f:
\prg_return_false:
\else:
@@ -1207,6 +1177,11 @@
% \begin{macrocode}
\prg_new_conditional:Npnn \@@_change_case_if_greek_accent:n #1 { TF , p }
{
+ \exp_args:Nf \@@_change_case_if_greek_accent:n
+ { \int_eval:n { \@@_codepoint_from_chars:Nw #1 } }
+ }
+\cs_new:Npn \@@_change_case_if_greek_accent:n #1
+ {
\if_int_compare:w #1 = "0300 \exp_stop_f:
\prg_return_true:
\else:
@@ -1236,6 +1211,11 @@
\prg_new_conditional:Npnn \@@_change_case_if_greek_diacritic:n
#1 { TF , p }
{
+ \exp_args:Nf \@@_change_case_if_greek_diacritic:n
+ { \int_eval:n { \@@_codepoint_from_chars:Nw #1 } }
+ }
+\cs_new:Npn \@@_change_case_if_greek_diacritic:n #1
+ {
\if_int_compare:w #1 = "0304 \exp_stop_f:
\prg_return_true:
\else:
@@ -1260,6 +1240,11 @@
}
\prg_new_conditional:Npnn \@@_change_case_if_takes_dialytika:n #1 { TF }
{
+ \exp_args:Nf \@@_change_case_if_takes_dialytika:n
+ { \int_eval:n { \@@_codepoint_from_chars:Nw #1 } }
+ }
+\cs_new:Npn \@@_change_case_if_takes_dialytika:n #1
+ {
\if_int_compare:w #1 = "0399 \exp_stop_f:
\prg_return_true:
\else:
@@ -1280,6 +1265,11 @@
}
\prg_new_conditional:Npnn \@@_change_case_if_takes_ypogegrammeni:n #1 { TF }
{
+ \exp_args:Nf \@@_change_case_if_takes_ypogegrammeni:n
+ { \int_eval:n { \@@_codepoint_from_chars:Nw #1 } }
+ }
+\cs_new:Npn \@@_change_case_if_takes_ypogegrammeni:n #1
+ {
\if_int_compare:w #1 = "03B1 \exp_stop_f:
\prg_return_true:
\else:
@@ -1317,60 +1307,79 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:Nnnw}
% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnN}
-% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnNw}
-% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:NnnN}
+% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnn}
+% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnw}
+% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnN}
% There is one special case in Greek that needs to be picked up based on
% being an isolated letter. We do that using a test similar to final sigma,
% but it has to fire off from the space grabber.
% \begin{macrocode}
-\bool_lazy_or:nnT
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
+\cs_new:Npn \@@_change_case_boundary_upper_el:Nnnw
+ #1#2#3#4 \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
+ }
+\cs_new:Npn \@@_change_case_boundary_upper_el:nnN #1#2#3
{
- \cs_new:Npn \@@_change_case_boundary_upper_el:Nnnw
- #1#2#3#4 \q_@@_recursion_stop
+ \token_if_cs:NTF #3
+ { \@@_change_case_loop:nnw {#1} {#2} }
{
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_boundary_upper_el:nnN }
- { \@@_change_case_loop:nnw }
- {#2} {#3} #4 \q_@@_recursion_stop
+ \@@_codepoint_process:nN
+ { \@@_change_case_boundary_upper_el:nnn {#1} {#2} }
}
- \cs_new:Npn \@@_change_case_boundary_upper_el:nnN #1#2#3
+ #3
+ }
+\cs_new:Npn \@@_change_case_boundary_upper_el:nnn #1#2#3
+ {
+ \bool_lazy_or:nnTF
+ { \@@_codepoint_compare_p:nNn {#3} = { "03AE } }
+ { \@@_codepoint_compare_p:nNn {#3} = { "1F22 } }
+ { \@@_change_case_boundary_upper_el:nnnw {#1} {#2} {#3} }
+ { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ }
+\cs_new:Npn \@@_change_case_boundary_upper_el:nnnw
+ #1#2#3#4 \q_@@_recursion_stop
+ {
+ \tl_if_head_is_N_type:nTF {#4}
+ { \@@_change_case_boundary_upper_el:nnnN {#3} }
{
- \bool_lazy_or:nnTF
- { \token_if_cs_p:N #3 }
+ \@@_change_case_store:e
{
- ! \bool_lazy_or_p:nn
- { \int_compare_p:nNn { `#3 } = { "03AE } }
- { \int_compare_p:nNn { `#3 } = { "1F22 } }
+ \codepoint_generate:nn { "0389 }
+ { \@@_change_case_catcode:nn {#3} { "0389 } }
}
- { \@@_change_case_loop:nnw }
- { \@@_change_case_boundary_upper_el:nnNw }
- {#1} {#2} #3
+ \@@_change_case_loop:nnw
}
- \cs_new:Npn \@@_change_case_boundary_upper_el:nnNw
- #1#2#3#4 \q_@@_recursion_stop
- {
- \tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_boundary_upper_el:NnnN #3 }
- {
- \@@_change_case_store:e
- { \char_generate:nn { "0389 } { \@@_char_catcode:N #3 } }
- \@@_change_case_loop:nnw
- }
- {#1} {#2} #4 \q_@@_recursion_stop
+ {#1} {#2} #4 \q_@@_recursion_stop
+ }
+\cs_new:Npn \@@_change_case_boundary_upper_el:nnnN #1#2#3#4
+ {
+ \MARJ
+ \bool_lazy_or:nnTF
+ { \token_if_letter_p:N #4 }
+ {
+ \bool_lazy_and_p:nn
+ { \token_if_active_p:N #4 }
+ { ! \int_compare_p:nNn {`#4} < { "80 } }
}
- \cs_new:Npn \@@_change_case_boundary_upper_el:NnnN #1#2#3#4
+ { \@@_change_case_loop:nnw {#2} {#3} #1#4 }
{
- \token_if_letter:NTF #4
- { \@@_change_case_loop:nnw {#2} {#3} #1#4 }
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
- { \char_generate:nn { "0389 } { \@@_char_catcode:N #1 } }
- \@@_change_case_loop:nnw {#2} {#3} #4
+ \codepoint_generate:nn { "0389 }
+ { \@@_change_case_catcode:nn {#1} { "0389 } }
}
+ \@@_change_case_loop:nnw {#2} {#3} #4
}
}
% \end{macrocode}
@@ -1378,98 +1387,89 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \begin{macro}[EXP]{\@@_change_case_title_el:nnnN}
+% \end{macro}
+% \begin{macro}[EXP]{\@@_change_case_title_el:nnnn}
% Titlecasing retains accents, but to prevent the uppercasing code
% from kicking in, there has to be an explicit function here.
% \begin{macrocode}
-\bool_lazy_or:nnT
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
- {
- \cs_new:Npn \@@_change_case_title_el:nnnN #1#2#3#4
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
- }
+\cs_new:Npn \@@_change_case_title_el:nnnn #1#2#3#4
+ { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
% \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:nnnn ,
+% \@@_change_case_title_hy:nnnn ,
+% \@@_change_case_upper_hy-x-yiwn:nnnn ,
+% \@@_change_case_title_hy-x-yiwn:nnnn
% }
% See \url{https://www.unicode.org/L2/L2020/20143-armenian-ech-yiwn.pdf}.
% \begin{macrocode}
-\bool_lazy_or:nnT
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
+\cs_new:Npn \@@_change_case_upper_hy:nnnn #1#2#3#4
{
- \cs_new:cpn { @@_change_case_upper_hy:nnnN } #1#2#3#4
+ \@@_codepoint_compare:nNnTF {#4} = { "0587 }
{
- \int_compare:nNnTF { `#4 } = { "0587 }
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
- {
- \char_generate:nn { "0535 } { \@@_char_catcode:N #4 }
- \char_generate:nn { "054E } { \@@_char_catcode:N #4 }
- }
- \use:c { @@_change_case_char_next_ #2 :nn }
- {#2} {#3}
+ \codepoint_generate:nn { "0535 }
+ { \@@_change_case_catcode:nn {#4} { "0535 } }
+ \codepoint_generate:nn { "054E }
+ { \@@_change_case_catcode:nn {#4} { "054E } }
}
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+ \use:c { @@_change_case_next_ #2 :nn }
+ {#2} {#3}
}
- \cs_new:cpn { @@_change_case_title_hy:nnnN } #1#2#3#4
+ { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
+ }
+\cs_new:Npn \@@_change_case_title_hy:nnnn #1#2#3#4
+ {
+ \@@_codepoint_compare:nNnTF {#4} = { "0587 }
{
- \int_compare:nNnTF { `#4 } = { "0587 }
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
- {
- \char_generate:nn { "0535 } { \@@_char_catcode:N #4 }
- \char_generate:nn { "057E } { \@@_char_catcode:N #4 }
- }
- \use:c { @@_change_case_char_next_ #2 :nn }
- {#2} {#3}
+ \codepoint_generate:nn { "0535 }
+ { \@@_change_case_catcode:nn {#4} { "0535 } }
+ \codepoint_generate:nn { "057E }
+ { \@@_change_case_catcode:nn {#4} { "057E } }
}
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+ \use:c { @@_change_case_next_ #2 :nn }
+ {#2} {#3}
}
- \cs_new:cpn { @@_change_case_upper_hy-x-yiwn:nnnN } #1#2#3#4
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
- \cs_new_eq:cc { @@_change_case_title_hy-x-yiwn:nnnN }
- { @@_change_case_upper_hy-x-yiwn:nnnN }
+ { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
}
+\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 }
% \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:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_upper_la-x-medieval:nnnn}
% Simply swaps of characters.
% \begin{macrocode}
-\cs_new:cpn { @@_change_case_lower_la-x-medieval:nnnN } #1#2#3#4
+\cs_new:cpn { @@_change_case_lower_la-x-medieval:nnnn } #1#2#3#4
{
- \int_compare:nNnTF { `#4 } = { `V }
+ \@@_codepoint_compare:nNnTF {#4} = { "0056 }
{
\@@_change_case_store:e
- {
- \char_generate:nn { `u } { \@@_char_catcode:N #4 }
- }
- \use:c { @@_change_case_char_next_ #2 :nn }
+ { \char_generate:nn { "0075 } { \@@_char_catcode:N #4 } }
+ \use:c { @@_change_case_next_ #2 :nn }
{#2} {#3}
}
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+ { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
}
-\cs_new:cpn { @@_change_case_upper_la-x-medieval:nnnN } #1#2#3#4
+\cs_new:cpn { @@_change_case_upper_la-x-medieval:nnnn } #1#2#3#4
{
- \int_compare:nNnTF { `#4 } = { `u }
+ \@@_codepoint_compare:nNnTF {#4} = { "0075 }
{
\@@_change_case_store:e
- {
- \char_generate:nn { `V } { \@@_char_catcode:N #4 }
- }
- \use:c { @@_change_case_char_next_ #2 :nn }
+ { \char_generate:nn { "0056 } { \@@_char_catcode:N #4 } }
+ \use:c { @@_change_case_next_ #2 :nn }
{#2} {#3}
}
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+ { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
}
% \end{macrocode}
% \end{macro}
@@ -1477,191 +1477,223 @@
%
% \begin{macro}[EXP]
% {
-% \@@_change_cases_lower_lt:nnnN ,
-% \@@_change_cases_lower_lt_auxi:nnnN ,
-% \@@_change_cases_lower_lt_auxii:nnnN
+% \@@_change_cases_lower_lt:nnnn ,
+% \@@_change_cases_lower_lt_auxi:nnnn ,
+% \@@_change_cases_lower_lt_auxii:nnnn
% }
% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnw}
% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnN}
+% \begin{macro}[rEXP]{\@@_change_case_lower_lt:nnn}
% 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}
-\bool_lazy_or:nnT
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
+\cs_new:Npn \@@_change_case_lower_lt:nnnn #1#2#3#4
{
- \cs_new:Npn \@@_change_case_lower_lt:nnnN #1#2#3#4
- {
- \exp_args:Ne \@@_change_case_lower_lt_auxi:nnnN
+ \exp_args:Ne \@@_change_case_lower_lt_auxi:nnnn
+ {
+ \int_case:nn { \@@_codepoint_from_chars:Nw #4 }
{
- \int_case:nn { `#4 }
- {
- { "00CC } { "0300 }
- { "00CD } { "0301 }
- { "0128 } { "0303 }
- }
- }
- {#2} {#3} #4
+ { "00CC } { "0300 }
+ { "00CD } { "0301 }
+ { "0128 } { "0303 }
+ }
}
+ {#2} {#3} {#4}
+ }
% \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 and 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:nnnn #1#2#3#4
+ {
+ \tl_if_blank:nTF {#1}
{
- \tl_if_blank:nTF {#1}
+ \exp_args:Ne \@@_change_case_lower_lt_auxii:nnnn
{
- \exp_args:Ne \@@_change_case_lower_lt_auxii:nnnN
+ \int_case:nn { \@@_codepoint_from_chars:Nw #4 }
{
- \int_case:nn { `#4 }
- {
- { "0049 } { "0069 }
- { "004A } { "006A }
- { "012E } { "012F }
- }
- }
- {#2} {#3} #4
+ { "0049 } { "0069 }
+ { "004A } { "006A }
+ { "012E } { "012F }
+ }
}
+ {#2} {#3} {#4}
+ }
+ {
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
- {
- \char_generate:nn { "0069 } { \@@_char_catcode:N #4 }
- \char_generate:nn { "0307 } { \@@_char_catcode:N #4 }
- \char_generate:nn {#1} { \@@_char_catcode:N #4 }
- }
- \@@_change_case_loop:nnw {#2} {#3}
+ \codepoint_generate:nn { "0069 }
+ { \@@_change_case_catcode:nn {#4} { "0069 } }
+ \codepoint_generate:nn { "0307 }
+ { \@@_change_case_catcode:nn {#4} { "0307 } }
+ \codepoint_generate:nn {#1}
+ { \@@_change_case_catcode:nn {#4} {#1} }
}
+ \@@_change_case_loop:nnw {#2} {#3}
}
+ }
% \end{macrocode}
% Again, branch depending on a hit. If there is one, we output the character
% 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:nnnn #1#2#3#4
+ {
+ \tl_if_blank:nTF {#1}
+ { \@@_change_case_codepoint:nnnn {#2} {#2} {#3} {#4} }
{
- \tl_if_blank:nTF {#1}
- { \@@_change_case_lower_sigma:nnnN {#2} {#2} {#3} #4 }
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
- { \char_generate:nn {#1} { \@@_char_catcode:N #4 } }
- \@@_change_case_lower_lt:nnw {#2} {#3}
+ \codepoint_generate:nn {#1}
+ { \@@_change_case_catcode:nn {#4} {#1} }
}
+ \@@_change_case_lower_lt:nnw {#2} {#3}
}
- \cs_new:Npn \@@_change_case_lower_lt:nnw #1#2#3 \q_@@_recursion_stop
+ }
+\cs_new:Npn \@@_change_case_lower_lt:nnw #1#2#3 \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
+ }
+\cs_new:Npn \@@_change_case_lower_lt:nnN #1#2#3
+ {
+ \@@_codepoint_process:nN
+ { \@@_change_case_lower_lt:nnn {#1} {#2} } #3
+ }
+\cs_new:Npn \@@_change_case_lower_lt:nnn #1#2#3
+ {
+ \bool_lazy_and:nnT
{
- \tl_if_head_is_N_type:nTF {#3}
- { \@@_change_case_lower_lt:nnN }
- { \@@_change_case_loop:nnw }
- {#1} {#2} #3 \q_@@_recursion_stop
+ \bool_lazy_or_p:nn
+ { ! \tl_if_single_p:n {#3} }
+ { ! \token_if_cs_p:N #3 }
}
- \cs_new:Npn \@@_change_case_lower_lt:nnN #1#2#3
{
- \bool_lazy_and:nnT
- { ! \token_if_cs_p:N #3 }
+ \bool_lazy_any_p:n
{
- \bool_lazy_any_p:n
- {
- { \int_compare_p:nNn { `#3 } = { "0300 } }
- { \int_compare_p:nNn { `#3 } = { "0301 } }
- { \int_compare_p:nNn { `#3 } = { "0303 } }
- }
+ { \@@_codepoint_compare_p:nNn {#3} = { "0300 } }
+ { \@@_codepoint_compare_p:nNn {#3} = { "0301 } }
+ { \@@_codepoint_compare_p:nNn {#3} = { "0303 } }
}
+ }
+ {
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
- { \char_generate:nn { "0307 } { \@@_char_catcode:N #3 } }
+ \codepoint_generate:nn { "0307 }
+ { \@@_change_case_catcode:nn {#3} { "0307 } }
}
- \@@_change_case_loop:nnw {#1} {#2} #3
}
+ \@@_change_case_loop:nnw {#1} {#2} #3
}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
% \begin{macro}[EXP]
% {
-% \@@_change_cases_upper_lt:nnnN ,
-% \@@_change_cases_upper_lt_aux:nnnN
+% \@@_change_cases_upper_lt:nnnn ,
+% \@@_change_cases_upper_lt_aux:nnnn
% }
% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnw}
% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnN}
+% \begin{macro}[rEXP]{\@@_change_case_upper_lt:nnn}
% The uppercasing version: first find i/j/i-ogonek, then look for the
% combining char: drop it if present.
% \begin{macrocode}
-\bool_lazy_or:nnT
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
- {
- \cs_new:Npn \@@_change_case_upper_lt:nnnN #1#2#3#4
- {
- \exp_args:Ne \@@_change_case_upper_lt_aux:nnnN
+\cs_new:Npn \@@_change_case_upper_lt:nnnn #1#2#3#4
+ {
+ \exp_args:Ne \@@_change_case_upper_lt_aux:nnnn
+ {
+ \int_case:nn { \@@_codepoint_from_chars:Nw #4 }
{
- \int_case:nn { `#4 }
- {
- { "0069 } { "0049 }
- { "006A } { "004A }
- { "012F } { "012E }
- }
- }
- {#2} {#3} #4
+ { "0069 } { "0049 }
+ { "006A } { "004A }
+ { "012F } { "012E }
+ }
}
- \cs_new:Npn \@@_change_case_upper_lt_aux:nnnN #1#2#3#4
- {
- \tl_if_blank:nTF {#1}
- { \@@_change_case_char:nnnN { upper } {#2} {#3} #4 }
- {
- \@@_change_case_store:e
- { \char_generate:nn {#1} { \@@_char_catcode:N #4 } }
- \@@_change_case_upper_lt:nnw {#2} {#3}
- }
- }
- \cs_new:Npn \@@_change_case_upper_lt:nnw #1#2#3 \q_@@_recursion_stop
+ {#2} {#3} {#4}
+ }
+\cs_new:Npn \@@_change_case_upper_lt_aux:nnnn #1#2#3#4
+ {
+ \tl_if_blank:nTF {#1}
+ { \@@_change_case_codepoint:nnnn { upper } {#2} {#3} {#4} }
{
- \tl_if_head_is_N_type:nTF {#3}
- { \@@_change_case_upper_lt:nnN }
- { \use:c { @@_change_case_char_next_ #1 :nn } }
- {#1} {#2} #3 \q_@@_recursion_stop
+ \@@_change_case_store:e
+ {
+ \codepoint_generate:nn {#1}
+ { \@@_change_case_catcode:nn {#4} {#1} }
+ }
+ \@@_change_case_upper_lt:nnw {#2} {#3}
}
- \cs_new:Npn \@@_change_case_upper_lt:nnN #1#2#3
+ }
+\cs_new:Npn \@@_change_case_upper_lt:nnw #1#2#3 \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
+ }
+\cs_new:Npn \@@_change_case_upper_lt:nnN #1#2#3
+ {
+ \@@_codepoint_process:nN
+ { \@@_change_case_upper_lt:nnn {#1} {#2} } #3
+ }
+\cs_new:Npn \@@_change_case_upper_lt:nnn #1#2#3
+ {
+ \bool_lazy_and:nnTF
{
- \bool_lazy_and:nnTF
+ \bool_lazy_or_p:nn
+ { ! \tl_if_single_p:n {#3} }
{ ! \token_if_cs_p:N #3 }
- { \int_compare_p:nNn { `#3 } = { "0307 } }
- { \use:c { @@_change_case_char_next_ #1 :nn } {#1} {#2} }
- { \use:c { @@_change_case_char_next_ #1 :nn } {#1} {#2} #3 }
}
+ { \@@_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 }
}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
%
-% \begin{macro}[EXP]{\@@_change_case_title_nl:nnnN}
+% \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}
% 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:nnnn #1#2#3#4
+ {
+ \tl_if_single:nTF {#4}
+ { \@@_change_case_title_nl_aux:nnnn }
+ { \@@_change_case_codepoint:nnnn }
+ {#1} {#2} {#3} {#4}
+ }
+\cs_new:Npn \@@_change_case_title_nl_aux:nnnn #1#2#3#4
{
\bool_lazy_or:nnTF
- { \int_compare_p:nNn { `#4 } = { "0049 } }
- { \int_compare_p:nNn { `#4 } = { "0069 } }
+ { \int_compare_p:nNn {`#4} = { "0049 } }
+ { \int_compare_p:nNn {`#4} = { "0069 } }
{
\@@_change_case_store:e
{ \char_generate:nn { "0049 } { \@@_char_catcode:N #4 } }
\@@_change_case_title_nl:nnw {#2} {#3}
}
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+ { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
}
\cs_new:Npn \@@_change_case_title_nl:nnw #1#2#3 \q_@@_recursion_stop
{
\tl_if_head_is_N_type:nTF {#3}
{ \@@_change_case_title_nl:nnN }
- { \use:c { @@_change_case_char_next_ #1 :nn } }
+ { \use:c { @@_change_case_next_ #1 :nn } }
{#1} {#2} #3 \q_@@_recursion_stop
}
\cs_new:Npn \@@_change_case_title_nl:nnN #1#2#3
@@ -1670,118 +1702,96 @@
{ ! \token_if_cs_p:N #3 }
{
\bool_lazy_or_p:nn
- { \int_compare_p:nNn { `#3 } = { "004A } }
- { \int_compare_p:nNn { `#3 } = { "006A } }
+ { \int_compare_p:nNn {`#3} = { "004A } }
+ { \int_compare_p:nNn {`#3} = { "006A } }
}
{
\@@_change_case_store:e
{ \char_generate:nn { "004A } { \@@_char_catcode:N #3 } }
- \use:c { @@_change_case_char_next_ #1 :nn } {#1} {#2}
+ \use:c { @@_change_case_next_ #1 :nn } {#1} {#2}
}
- { \use:c { @@_change_case_char_next_ #1 :nn } {#1} {#2} #3 }
+ { \use:c { @@_change_case_next_ #1 :nn } {#1} {#2} #3 }
}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_change_case_lower_tr:nnnN}
+% \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:nnnNN}
+% \begin{macro}[EXP]{\@@_change_case_lower_tr:Nnnn}
% 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}
-\bool_lazy_or:nnTF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
+\cs_new:Npn \@@_change_case_lower_tr:nnnn #1#2#3#4
{
- \cs_new:Npn \@@_change_case_lower_tr:nnnN #1#2#3#4
+ \@@_codepoint_compare:nNnTF {#4} = { "0049 }
+ { \@@_change_case_lower_tr:nnNw {#1} {#3} #4 }
{
- \int_compare:nNnTF { `#4 } = { "0049 }
- { \@@_change_case_lower_tr:nnNw {#1} {#3} #4 }
+ \@@_codepoint_compare:nNnTF {#4} = { "0130 }
{
- \int_compare:nNnTF { `#4 } = { "0130 }
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
- { \char_generate:nn { "0069 } { \@@_char_catcode:N #4 } }
- \@@_change_case_loop:nnw {#1} {#3}
+ \codepoint_generate:nn { "0069 }
+ { \@@_change_case_catcode:nn {#4} { "0069 } }
}
- { \@@_change_case_lower_sigma:nnnN {#1} {#2} {#3} #4 }
+ \@@_change_case_loop:nnw {#1} {#3}
}
+ { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
}
+ }
% \end{macrocode}
% After a dotless-I there may be a dot-above character. If there is then
% a dotted-i should be produced, otherwise output a dotless-i. When the
% 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:nnNw #1#2#3#4 \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 {#4}
- { \@@_change_case_lower_tr:NnnN #3 }
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
- { \char_generate:nn { "0131 } { \@@_char_catcode:N #3 } }
- \@@_change_case_loop:nnw
+ \codepoint_generate:nn { "0131 }
+ { \@@_change_case_catcode:nn {#3} { "0131 } }
}
- {#1} {#2} #4 \q_@@_recursion_stop
+ \@@_change_case_loop:nnw {#1} {#2}
}
- \cs_new:Npn \@@_change_case_lower_tr:NnnN #1#2#3#4
+ #4 \q_@@_recursion_stop
+ }
+\cs_new:Npn \@@_change_case_lower_tr:NnnN #1#2#3#4
+ {
+ \@@_codepoint_process:nN
+ { \@@_change_case_lower_tr:Nnnn #1 {#2} {#3} } #4
+ }
+\cs_new:Npn \@@_change_case_lower_tr:Nnnn #1#2#3#4
+ {
+ \bool_lazy_or:nnTF
{
- \bool_lazy_or:nnTF
+ \bool_lazy_and_p:nn
+ { \tl_if_single_p:n {#4} }
{ \token_if_cs_p:N #4 }
- { ! \int_compare_p:nNn { `#4 } = { "0307 } }
- {
- \@@_change_case_store:e
- { \char_generate:nn { "0131 } { \@@_char_catcode:N #1 } }
- \@@_change_case_loop:nnw {#2} {#3} #4
- }
- {
- \@@_change_case_store:e
- { \char_generate:nn { "0069 } { \@@_char_catcode:N #1 } }
- \@@_change_case_loop:nnw {#2} {#3}
- }
}
- }
-% \end{macrocode}
-% For $8$-bit engines, dot-above is not available so there is a simple
-% test for an upper-case I. Then we can look for the UTF-8 representation of
-% an upper case dotted-I without the combining char. If it's not there,
-% preserve the UTF-8 sequence as-is. With $8$bit engines, we cannot
-% completely preserve category codes, so we have to make some assumptions:
-% output a \enquote{normal} \texttt{i} for the dotted case. As the original
-% character here is catcode-$13$, we have to make a choice about handling
-% of |i|: generate a \enquote{normal} one.
-% \begin{macrocode}
- {
- \cs_new:Npn \@@_change_case_lower_tr:nnnN #1#2#3#4
+ { ! \@@_codepoint_compare_p:nNn {#4} = { "0307 } }
{
- \int_compare:nNnTF { `#4 } = { "0049 }
- {
- \@@_change_case_store:V \c_@@_dotless_i_tl
- \@@_change_case_loop:nnw {#1} {#3}
- }
+ \@@_change_case_store:e
{
- \int_compare:nNnTF { `#4 } = { "00C4 }
- { \@@_change_case_lower_tr:nnnNN {#1} {#2} {#3} #4 }
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+ \codepoint_generate:nn { "0131 }
+ { \@@_change_case_catcode:nn {#1} { "0131 } }
}
+ \@@_change_case_loop:nnw {#2} {#3} #4
}
- \cs_new:Npn \@@_change_case_lower_tr:nnnNN #1#2#3#4#5
{
- \int_compare:nNnTF { `#5 } = { "00B0 }
+ \@@_change_case_store:e
{
- \@@_change_case_store:e
- {
- \char_generate:nn { "0069 }
- { \char_value_catcode:n { "0069 } }
- }
- \@@_change_case_loop:nnw {#1} {#3}
+ \codepoint_generate:nn { "0069 }
+ { \@@_change_case_catcode:nn {#1} { "0069 } }
}
- { \@@_change_case_char:nnnN {#1} {#2} {#3} #4#5 }
+ \@@_change_case_loop:nnw {#2} {#3}
}
}
% \end{macrocode}
@@ -1789,1055 +1799,36 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \begin{macro}[EXP]{\@@_change_case_upper_tr:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_upper_tr:nnnn}
% Uppercasing is easier: just one exception with no context.
% \begin{macrocode}
-\cs_new:Npx \@@_change_case_upper_tr:nnnN #1#2#3#4
+\cs_new:Npn \@@_change_case_upper_tr:nnnn #1#2#3#4
{
- \exp_not:N \int_compare:nNnTF { `#4 } = { "0069 }
+ \@@_codepoint_compare:nNnTF {#4} = { "0069 }
{
- \bool_lazy_or:nnTF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
- {
- \exp_not:N \@@_change_case_store:e
- {
- \exp_not:N \char_generate:nn { "0130 }
- { \exp_not:N \@@_char_catcode:N #4 }
- }
- }
+ \@@_change_case_store:e
{
- \exp_not:N \@@_change_case_store:V
- \exp_not:N \c_@@_dotted_I_tl
+ \codepoint_generate:nn { "0130 }
+ { \@@_change_case_catcode:nn {#4} { "0130 } }
}
- \exp_not:N \use:c { @@_change_case_char_next_ #2 :nn } {#2} {#3}
+ \use:c { @@_change_case_next_ #2 :nn } {#2} {#3}
}
- { \exp_not:N \@@_change_case_char:nnnN {#1} {#2} {#3} #4 }
+ { \@@_change_case_codepoint:nnnn {#1} {#2} {#3} {#4} }
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]
-% {\@@_change_case_lower_az:nnnN, \@@_change_case_upper_az:nnnN}
+% {\@@_change_case_lower_az:nnnn, \@@_change_case_upper_az:nnnn}
% 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:nnnn
+ \@@_change_case_lower_tr:nnnn
+\cs_new_eq:NN \@@_change_case_upper_az:nnnn
+ \@@_change_case_upper_tr:nnnn
% \end{macrocode}
% \end{macro}
%
-% \subsection{Case changing data for $8$-bit engines}
-%
-% \begin{variable}
-% {
-% \c_@@_dotless_i_tl ,
-% \c_@@_dotted_I_tl ,
-% \c_@@_i_ogonek_tl ,
-% \c_@@_I_ogonek_tl ,
-% \c_@@_final_sigma_tl ,
-% \c_@@_sigma_tl ,
-% \c_@@_grosses_Eszett_tl
-% }
-% For cases where there is an $8$-bit option in the |T1| font set up,
-% a variant is provided in both cases. There are also a few extras for
-% |LGR|.
-% \begin{macrocode}
-\group_begin:
- \bool_lazy_or:nnF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
- {
- \cs_set_protected:Npn \@@_tmp:w #1#2
- {
- \group_begin:
- \cs_set_protected:Npn \@@_tmp:w ##1##2##3##4
- {
- \tl_const:Nx #1
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {##1} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {##2} { 13 }
- \tl_if_blank:nF {##3}
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {##3} { 13 }
- }
- }
- }
- \use:x
- { \@@_tmp:w \char_to_utfviii_bytes:n { "#2 } }
- \group_end:
- }
- \@@_tmp:w \c_@@_dotless_i_tl { 0131 }
- \@@_tmp:w \c_@@_dotted_I_tl { 0130 }
- \@@_tmp:w \c_@@_i_ogonek_tl { 012F }
- \@@_tmp:w \c_@@_I_ogonek_tl { 012E }
- \@@_tmp:w \c_@@_final_sigma_tl { 03C2 }
- \@@_tmp:w \c_@@_sigma_tl { 03C3 }
- \@@_tmp:w \c_@@_grosses_Eszett_tl { 1E9E }
- }
-\group_end:
-% \end{macrocode}
-% \end{variable}
-%
-% For $8$-bit engines we now need to define the case-change data for
-% the multi-octet mappings. This data is here not in the \pkg{char} module
-% as the multi-byte nature means they are never |N|-type. As this data is
-% needed both for text and string work, it is stored as |kernel|: it remains
-% internal as it is not really suitable for wider exposure.
-%
-% The first set of codepoints are those in |T1|: all of these are two bytes.
-% \begin{macrocode}
-\group_begin:
- \bool_lazy_or:nnF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
- {
- \cs_set_protected:Npn \@@_loop:nn #1#2
- {
- \quark_if_recursion_tail_stop:n {#1}
- \use:x
- {
- \@@_tmp:w
- \char_to_utfviii_bytes:n { "#1 }
- \char_to_utfviii_bytes:n { "#2 }
- }
- \@@_loop:nn
- }
- \cs_set_protected:Npn \@@_tmp:nnnn #1#2#3#4#5
- {
- \tl_const:cx
- {
- c__kernel_ #1 case_
- \char_generate:nn {#2} { 12 }
- \char_generate:nn {#3} { 12 }
- _tl
- }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#4} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#5} { 13 }
- }
- }
- \cs_set_protected:Npn \@@_tmp:w #1#2#3#4#5#6#7#8
- {
- \tl_const:cx
- {
- c__kernel_lowercase_
- \char_generate:nn {#1} { 12 }
- \char_generate:nn {#2} { 12 }
- _tl
- }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#5} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#6} { 13 }
- }
- \@@_tmp:nnnn { upper } {#5} {#6} {#1} {#2}
- \@@_tmp:nnnn { title } {#5} {#6} {#1} {#2}
- }
- \@@_loop:nn
- { 00C0 } { 00E0 }
- { 00C1 } { 00E1 }
- { 00C2 } { 00E2 }
- { 00C3 } { 00E3 }
- { 00C4 } { 00E4 }
- { 00C5 } { 00E5 }
- { 00C6 } { 00E6 }
- { 00C7 } { 00E7 }
- { 00C8 } { 00E8 }
- { 00C9 } { 00E9 }
- { 00CA } { 00EA }
- { 00CB } { 00EB }
- { 00CC } { 00EC }
- { 00CD } { 00ED }
- { 00CE } { 00EE }
- { 00CF } { 00EF }
- { 00D0 } { 00F0 }
- { 00D1 } { 00F1 }
- { 00D2 } { 00F2 }
- { 00D3 } { 00F3 }
- { 00D4 } { 00F4 }
- { 00D5 } { 00F5 }
- { 00D6 } { 00F6 }
- { 00D8 } { 00F8 }
- { 00D9 } { 00F9 }
- { 00DA } { 00FA }
- { 00DB } { 00FB }
- { 00DC } { 00FC }
- { 00DD } { 00FD }
- { 00DE } { 00FE }
- { 0100 } { 0101 }
- { 0102 } { 0103 }
- { 0104 } { 0105 }
- { 0106 } { 0107 }
- { 0108 } { 0109 }
- { 010A } { 010B }
- { 010C } { 010D }
- { 010E } { 010F }
- { 0110 } { 0111 }
- { 0112 } { 0113 }
- { 0114 } { 0115 }
- { 0116 } { 0117 }
- { 0118 } { 0119 }
- { 011A } { 011B }
- { 011C } { 011D }
- { 011E } { 011F }
- { 0120 } { 0121 }
- { 0122 } { 0123 }
- { 0124 } { 0125 }
- { 0128 } { 0129 }
- { 012A } { 012B }
- { 012C } { 012D }
- { 012E } { 012F }
- { 0132 } { 0133 }
- { 0134 } { 0135 }
- { 0136 } { 0137 }
- { 0139 } { 013A }
- { 013B } { 013C }
- { 013E } { 013F }
- { 0141 } { 0142 }
- { 0143 } { 0144 }
- { 0145 } { 0146 }
- { 0147 } { 0148 }
- { 014A } { 014B }
- { 014C } { 014D }
- { 014E } { 014F }
- { 0150 } { 0151 }
- { 0152 } { 0153 }
- { 0154 } { 0155 }
- { 0156 } { 0157 }
- { 0158 } { 0159 }
- { 015A } { 015B }
- { 015C } { 015D }
- { 015E } { 015F }
- { 0160 } { 0161 }
- { 0162 } { 0163 }
- { 0164 } { 0165 }
- { 0168 } { 0169 }
- { 016A } { 016B }
- { 016C } { 016D }
- { 016E } { 016F }
- { 0170 } { 0171 }
- { 0172 } { 0173 }
- { 0174 } { 0175 }
- { 0176 } { 0177 }
- { 0178 } { 00FF }
- { 0179 } { 017A }
- { 017B } { 017C }
- { 017D } { 017E }
- { 01A0 } { 01A1 }
- { 01AF } { 01B0 }
- { 01CD } { 01CE }
- { 01CF } { 01D0 }
- { 01D1 } { 01D2 }
- { 01D3 } { 01D4 }
- { 01E2 } { 01E3 }
- { 01E6 } { 01E7 }
- { 01E8 } { 01E9 }
- { 01EA } { 01EB }
- { 01F4 } { 01F5 }
- { 0218 } { 0219 }
- { 021A } { 021B }
-% \end{macrocode}
-% Add |T2| (Cyrillic) : again two bytes.
-% \begin{macrocode}
- { 0400 } { 0450 }
- { 0401 } { 0451 }
- { 0402 } { 0452 }
- { 0403 } { 0453 }
- { 0404 } { 0454 }
- { 0405 } { 0455 }
- { 0406 } { 0456 }
- { 0407 } { 0457 }
- { 0408 } { 0458 }
- { 0409 } { 0459 }
- { 040A } { 045A }
- { 040B } { 045B }
- { 040C } { 045C }
- { 040D } { 045D }
- { 040E } { 045E }
- { 040F } { 045F }
- { 0410 } { 0430 }
- { 0411 } { 0431 }
- { 0412 } { 0432 }
- { 0413 } { 0433 }
- { 0414 } { 0434 }
- { 0415 } { 0435 }
- { 0416 } { 0436 }
- { 0417 } { 0437 }
- { 0418 } { 0438 }
- { 0419 } { 0439 }
- { 041A } { 043A }
- { 041B } { 043B }
- { 041C } { 043C }
- { 041D } { 043D }
- { 041E } { 043E }
- { 041F } { 043F }
- { 0420 } { 0440 }
- { 0421 } { 0441 }
- { 0422 } { 0442 }
- { 0423 } { 0443 }
- { 0424 } { 0444 }
- { 0425 } { 0445 }
- { 0426 } { 0446 }
- { 0427 } { 0447 }
- { 0428 } { 0448 }
- { 0429 } { 0449 }
- { 042A } { 044A }
- { 042B } { 044B }
- { 042C } { 044C }
- { 042D } { 044D }
- { 042E } { 044E }
- { 042F } { 044F }
-% \end{macrocode}
-% Greek support: everything in the two-octet range.
-% \begin{macrocode}
- { 0370 } { 0371 }
- { 0372 } { 0373 }
- { 0376 } { 0377 }
- { 03FD } { 037B }
- { 03FE } { 037C }
- { 03FF } { 037D }
- { 0386 } { 03AC }
- { 0388 } { 03AD }
- { 0389 } { 03AE }
- { 038A } { 03AF }
- { 0391 } { 03B1 }
- { 0392 } { 03B2 }
- { 0393 } { 03B3 }
- { 0394 } { 03B4 }
- { 0395 } { 03B5 }
- { 0396 } { 03B6 }
- { 0397 } { 03B7 }
- { 0398 } { 03B8 }
- { 0399 } { 03B9 }
- { 039A } { 03BA }
- { 039B } { 03BB }
- { 039C } { 03BC }
- { 039D } { 03BD }
- { 039E } { 03BE }
- { 039F } { 03BF }
- { 03A0 } { 03C0 }
- { 03A1 } { 03C1 }
- { 03A3 } { 03C3 }
- { 03A4 } { 03C4 }
- { 03A5 } { 03C5 }
- { 03A6 } { 03C6 }
- { 03A7 } { 03C7 }
- { 03A8 } { 03C8 }
- { 03A9 } { 03C9 }
- { 03AA } { 03CA }
- { 03AB } { 03CB }
- { 038C } { 03CC }
- { 038E } { 03CD }
- { 038F } { 03CE }
- { 03CF } { 03D7 }
- { 03D8 } { 03D9 }
- { 03DA } { 03DB }
- { 03DC } { 03DD }
- { 03DE } { 03DF }
- { 03E0 } { 03E1 }
- { 03E2 } { 03E3 }
- { 03E4 } { 03E5 }
- { 03E6 } { 03E7 }
- { 03E8 } { 03E9 }
- { 03EA } { 03EB }
- { 03EC } { 03ED }
- { 03EE } { 03EF }
- { 03F9 } { 03F2 }
- { 037F } { 03F3 }
- { 03F7 } { 03F8 }
- { 03FA } { 03FB }
- \q_recursion_tail ?
- \q_recursion_stop
-% \end{macrocode}
-% Odds and ends for Greek; mainly symbols that are for compatibility,
-% but also things like the terminal sigma. Almost all are uppercase
-% mappings, but there is one that is not!
-% \begin{macrocode}
- \cs_set_protected:Npn \@@_tmp:w #1#2#3
- {
- \group_begin:
- \cs_set_protected:Npn \@@_tmp:w ##1##2##3##4##5##6##7##8
- {
- \tl_const:cx
- {
- c__kernel_ #3 case_
- \char_generate:nn {##1} { 12 }
- \char_generate:nn {##2} { 12 }
- _tl
- }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {##5} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {##6} { 13 }
- }
- }
- \use:x
- {
- \@@_tmp:w
- \char_to_utfviii_bytes:n { "#1 }
- \char_to_utfviii_bytes:n { "#2 }
- }
- \group_end:
- }
- \@@_tmp:w { 0345 } { 0399 } { upper }
- \@@_tmp:w { 03C2 } { 03A3 } { upper }
- \@@_tmp:w { 03D0 } { 0392 } { upper }
- \@@_tmp:w { 03D1 } { 0398 } { upper }
- \@@_tmp:w { 03D5 } { 03A6 } { upper }
- \@@_tmp:w { 03D6 } { 03A0 } { upper }
- \@@_tmp:w { 03F0 } { 039A } { upper }
- \@@_tmp:w { 03F1 } { 03A1 } { upper }
- \@@_tmp:w { 03F4 } { 03B8 } { lower }
- \@@_tmp:w { 03F5 } { 0395 } { upper }
-% \end{macrocode}
-% Croatian digraph letters: these have a titlecase variant.
-% \begin{macrocode}
- \@@_tmp:w { 01C4 } { 01C5 } { title }
- \@@_tmp:w { 01C4 } { 01C6 } { lower }
- \@@_tmp:w { 01C5 } { 01C4 } { upper }
- \@@_tmp:w { 01C5 } { 01C6 } { lower }
- \@@_tmp:w { 01C6 } { 01C4 } { upper }
- \@@_tmp:w { 01C6 } { 01C5 } { title }
- \@@_tmp:w { 01C7 } { 01C8 } { title }
- \@@_tmp:w { 01C7 } { 01C9 } { lower }
- \@@_tmp:w { 01C8 } { 01C7 } { upper }
- \@@_tmp:w { 01C8 } { 01C9 } { lower }
- \@@_tmp:w { 01C9 } { 01C7 } { upper }
- \@@_tmp:w { 01C9 } { 01C8 } { title }
- \@@_tmp:w { 01CA } { 01CB } { title }
- \@@_tmp:w { 01CA } { 01CC } { lower }
- \@@_tmp:w { 01CB } { 01CA } { upper }
- \@@_tmp:w { 01CB } { 01CC } { lower }
- \@@_tmp:w { 01CC } { 01CA } { upper }
- \@@_tmp:w { 01CC } { 01CB } { title }
-% \end{macrocode}
-% Odds and ends that are not simple one-to-one mappings. These
-% are still two-octet code points.
-% \begin{macrocode}
- \cs_set_protected:Npn \@@_tmp:w #1#2#3
- {
- \group_begin:
- \cs_set_protected:Npn \@@_tmp:w ##1##2##3##4
- {
- \tl_const:cn
- {
- c__kernel_ #3 case_
- \char_generate:nn {##1} { 12 }
- \char_generate:nn {##2} { 12 }
- _tl
- }
- {#2}
- }
- \use:x
- { \@@_tmp:w \char_to_utfviii_bytes:n { "#1 } }
- \group_end:
- }
- \@@_tmp:w { 00DF } { SS } { upper }
- \@@_tmp:w { 00DF } { Ss } { title }
- \@@_tmp:w { 0131 } { I } { upper }
-% \end{macrocode}
-% Coverage for Vietnamese (\texttt{T5})
-% \begin{macrocode}
- \cs_set_protected:Npn \@@_tmp:nnnnnn #1#2#3#4#5#6#7
- {
- \tl_const:cx
- {
- c__kernel_ #1 case_
- \char_generate:nn {#2} { 12 }
- \char_generate:nn {#3} { 12 }
- \char_generate:nn {#4} { 12 }
- _tl
- }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#5} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#6} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#7} { 13 }
- }
- }
- \cs_set_protected:Npn \@@_tmp:w #1#2#3#4#5#6#7#8
- {
- \tl_const:cx
- {
- c__kernel_lowercase_
- \char_generate:nn {#1} { 12 }
- \char_generate:nn {#2} { 12 }
- \char_generate:nn {#3} { 12 }
- _tl
- }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#5} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#6} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#7} { 13 }
- }
- \@@_tmp:nnnnnn { upper } {#5} {#6} {#7} {#1} {#2} {#3}
- \@@_tmp:nnnnnn { title } {#5} {#6} {#7} {#1} {#2} {#3}
- }
- \@@_loop:nn
- { 1EA0 } { 1EA1 }
- { 1EA2 } { 1EA3 }
- { 1EA4 } { 1EA5 }
- { 1EA6 } { 1EA7 }
- { 1EA8 } { 1EA9 }
- { 1EAA } { 1EAB }
- { 1EAC } { 1EAD }
- { 1EAE } { 1EAF }
- { 1EB0 } { 1EB1 }
- { 1EB2 } { 1EB3 }
- { 1EB4 } { 1EB5 }
- { 1EB6 } { 1EB7 }
- { 1EB8 } { 1EB9 }
- { 1EBA } { 1EBB }
- { 1EBC } { 1EBD }
- { 1EBE } { 1EBF }
- { 1EC0 } { 1EC1 }
- { 1EC2 } { 1EC3 }
- { 1EC4 } { 1EC5 }
- { 1EC6 } { 1EC7 }
- { 1EC8 } { 1EC9 }
- { 1ECA } { 1ECB }
- { 1ECC } { 1ECD }
- { 1ECE } { 1ECF }
- { 1ED0 } { 1ED1 }
- { 1ED2 } { 1ED3 }
- { 1ED4 } { 1ED5 }
- { 1ED6 } { 1ED7 }
- { 1ED8 } { 1ED9 }
- { 1EDA } { 1EDB }
- { 1EDC } { 1EDD }
- { 1EDE } { 1EDF }
- { 1EE0 } { 1EE1 }
- { 1EE2 } { 1EE3 }
- { 1EE4 } { 1EE5 }
- { 1EE6 } { 1EE7 }
- { 1EE8 } { 1EE9 }
- { 1EEA } { 1EEB }
- { 1EEC } { 1EED }
- { 1EEE } { 1EEF }
- { 1EF0 } { 1EF1 }
- { 1EF2 } { 1EF3 }
- { 1EF4 } { 1EF5 }
- { 1EF6 } { 1EF7 }
- { 1EF8 } { 1EF9 }
- \q_recursion_tail ?
- \q_recursion_stop
-% \end{macrocode}
-% Greek support: the three-octet code points.
-% \begin{macrocode}
- \@@_loop:nn
- { 1F08 } { 1F00 }
- { 1F09 } { 1F01 }
- { 1F0A } { 1F02 }
- { 1F0B } { 1F03 }
- { 1F0C } { 1F04 }
- { 1F0D } { 1F05 }
- { 1F0E } { 1F06 }
- { 1F0F } { 1F07 }
- { 1F18 } { 1F10 }
- { 1F19 } { 1F11 }
- { 1F1A } { 1F12 }
- { 1F1B } { 1F13 }
- { 1F1C } { 1F14 }
- { 1F1D } { 1F15 }
- { 1F28 } { 1F20 }
- { 1F29 } { 1F21 }
- { 1F2A } { 1F22 }
- { 1F2B } { 1F23 }
- { 1F2C } { 1F24 }
- { 1F2D } { 1F25 }
- { 1F2E } { 1F26 }
- { 1F2F } { 1F27 }
- { 1F38 } { 1F30 }
- { 1F39 } { 1F31 }
- { 1F3A } { 1F32 }
- { 1F3B } { 1F33 }
- { 1F3C } { 1F34 }
- { 1F3D } { 1F35 }
- { 1F3E } { 1F36 }
- { 1F3F } { 1F37 }
- { 1F48 } { 1F40 }
- { 1F49 } { 1F41 }
- { 1F4A } { 1F42 }
- { 1F4B } { 1F43 }
- { 1F4C } { 1F44 }
- { 1F4D } { 1F45 }
- { 1F59 } { 1F51 }
- { 1F5B } { 1F53 }
- { 1F5D } { 1F55 }
- { 1F5F } { 1F57 }
- { 1F68 } { 1F60 }
- { 1F69 } { 1F61 }
- { 1F6A } { 1F62 }
- { 1F6B } { 1F63 }
- { 1F6C } { 1F64 }
- { 1F6D } { 1F65 }
- { 1F6E } { 1F66 }
- { 1F6F } { 1F67 }
- { 1FBA } { 1F70 }
- { 1FBB } { 1F71 }
- { 1FC8 } { 1F72 }
- { 1FC9 } { 1F73 }
- { 1FCA } { 1F74 }
- { 1FCB } { 1F75 }
- { 1FDA } { 1F76 }
- { 1FDB } { 1F77 }
- { 1FF8 } { 1F78 }
- { 1FF9 } { 1F79 }
- { 1FEA } { 1F7A }
- { 1FEB } { 1F7B }
- { 1FFA } { 1F7C }
- { 1FFB } { 1F7D }
- { 1F88 } { 1F80 }
- { 1F89 } { 1F81 }
- { 1F8A } { 1F82 }
- { 1F8B } { 1F83 }
- { 1F8C } { 1F84 }
- { 1F8D } { 1F85 }
- { 1F8E } { 1F86 }
- { 1F8F } { 1F87 }
- { 1F98 } { 1F90 }
- { 1F99 } { 1F91 }
- { 1F9A } { 1F92 }
- { 1F9B } { 1F93 }
- { 1F9C } { 1F94 }
- { 1F9D } { 1F95 }
- { 1F9E } { 1F96 }
- { 1F9F } { 1F97 }
- { 1FA8 } { 1FA0 }
- { 1FA9 } { 1FA1 }
- { 1FAA } { 1FA2 }
- { 1FAB } { 1FA3 }
- { 1FAC } { 1FA4 }
- { 1FAD } { 1FA5 }
- { 1FAE } { 1FA6 }
- { 1FAF } { 1FA7 }
- { 1FB8 } { 1FB0 }
- { 1FB9 } { 1FB1 }
- { 1FBC } { 1FB3 }
- { 1FCC } { 1FC3 }
- { 1FD8 } { 1FD0 }
- { 1FD9 } { 1FD1 }
- { 1FE8 } { 1FE0 }
- { 1FE9 } { 1FE1 }
- { 1FEC } { 1FE5 }
- { 1FFC } { 1FF3 }
- \q_recursion_tail ?
- \q_recursion_stop
-% \end{macrocode}
-% One three-octet special case for Greek: it also moves to two-octets!
-% \begin{macrocode}
- \cs_set_protected:Npn \@@_tmp:w #1#2#3
- {
- \group_begin:
- \cs_set_protected:Npn \@@_tmp:w ##1##2##3##4##5##6##7##8
- {
- \tl_const:cx
- {
- c__kernel_ #3 case_
- \char_generate:nn {##1} { 12 }
- \char_generate:nn {##2} { 12 }
- \char_generate:nn {##3} { 12 }
- _tl
- }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {##5} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {##6} { 13 }
- }
- }
- \use:x
- {
- \@@_tmp:w
- \char_to_utfviii_bytes:n { "#1 }
- \char_to_utfviii_bytes:n { "#2 }
- }
- \group_end:
- }
- \@@_tmp:w { 1FBE } { 0399 } { upper }
-% \end{macrocode}
-% Greek accent suppression for uppercasing.
-% \begin{macrocode}
- \cs_set_protected:Npn \@@_tmp:w #1#2#3#4#5#6#7#8
- {
- \tl_const:cx
- {
- c_@@_uppercase_el_
- \char_generate:nn {#1} { 12 }
- \char_generate:nn {#2} { 12 }
- _tl
- }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#5} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#6} { 13 }
- }
- }
- \@@_loop:nn
- { 0370 } { 0370 }
- { 0371 } { 0370 }
- { 0372 } { 0372 }
- { 0373 } { 0372 }
- { 0376 } { 0376 }
- { 0377 } { 0376 }
- { 03FD } { 03FD }
- { 037B } { 03FD }
- { 03FE } { 03FE }
- { 037C } { 03FE }
- { 03FF } { 03FF }
- { 037D } { 03FF }
- { 0386 } { 0391 }
- { 0388 } { 0395 }
- { 0389 } { 0397 }
- { 038A } { 0399 }
- { 038C } { 039F }
- { 038E } { 03A5 }
- { 038F } { 03A9 }
- { 0390 } { 03AA }
- { 0391 } { 0391 }
- { 0392 } { 0392 }
- { 0393 } { 0393 }
- { 0394 } { 0394 }
- { 0395 } { 0395 }
- { 0396 } { 0396 }
- { 0397 } { 0397 }
- { 0398 } { 0398 }
- { 0399 } { 0399 }
- { 039A } { 039A }
- { 039B } { 039B }
- { 039C } { 039C }
- { 039D } { 039D }
- { 039E } { 039E }
- { 039F } { 039F }
- { 03A0 } { 03A0 }
- { 03A1 } { 03A1 }
- { 03A3 } { 03A3 }
- { 03A4 } { 03A4 }
- { 03A5 } { 03A5 }
- { 03A6 } { 03A6 }
- { 03A7 } { 03A7 }
- { 03A8 } { 03A8 }
- { 03A9 } { 03A9 }
- { 03AA } { 03AA }
- { 03AB } { 03AB }
- { 03AC } { 0391 }
- { 03AD } { 0395 }
- { 03AE } { 0397 }
- { 03AF } { 0399 }
- { 03B0 } { 03AB }
- { 03B1 } { 0391 }
- { 03B2 } { 0392 }
- { 03B3 } { 0393 }
- { 03B4 } { 0394 }
- { 03B5 } { 0395 }
- { 03B6 } { 0396 }
- { 03B7 } { 0397 }
- { 03B8 } { 0398 }
- { 03B9 } { 0399 }
- { 03BA } { 039A }
- { 03BB } { 039B }
- { 03BC } { 039C }
- { 03BD } { 039D }
- { 03BE } { 039E }
- { 03BF } { 039F }
- { 03C0 } { 03A0 }
- { 03C1 } { 03A1 }
- { 03C2 } { 03A3 }
- { 03C3 } { 03A3 }
- { 03C4 } { 03A4 }
- { 03C5 } { 03A5 }
- { 03C6 } { 03A6 }
- { 03C7 } { 03A7 }
- { 03C8 } { 03A8 }
- { 03C9 } { 03A9 }
- { 03CA } { 03AA }
- { 03CB } { 03AB }
- { 03CC } { 039F }
- { 03CD } { 03A5 }
- { 03CE } { 03A9 }
- { 03D0 } { 0392 }
- { 03D1 } { 0398 }
- { 03D2 } { 03A5 }
- { 03D3 } { 03A5 }
- { 03D4 } { 03AB }
- { 03D5 } { 03A6 }
- { 03D6 } { 03A0 }
- { 03DA } { 03DA }
- { 03DB } { 03DA }
- { 03DC } { 03DC }
- { 03DD } { 03DC }
- { 03DE } { 03DE }
- { 03DF } { 03DE }
- { 03E0 } { 03E0 }
- { 03E1 } { 03E0 }
- { 03F0 } { 039A }
- { 03F1 } { 03A1 }
- { 03F2 } { 03F9 }
- { 03F9 } { 03F9 }
- \q_recursion_tail ?
- \q_recursion_stop
- \cs_set_protected:Npn \@@_tmp:w #1#2#3#4#5#6#7#8
- {
- \tl_const:cx
- {
- c_@@_uppercase_el_
- \char_generate:nn {#1} { 12 }
- \char_generate:nn {#2} { 12 }
- \char_generate:nn {#3} { 12 }
- _tl
- }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#5} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#6} { 13 }
- \tl_if_blank:nF {#7}
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#7} { 13 }
- }
- }
- }
- \@@_loop:nn
- { 1F00 } { 0391 }
- { 1F01 } { 0391 }
- { 1F02 } { 0391 }
- { 1F03 } { 0391 }
- { 1F04 } { 0391 }
- { 1F05 } { 0391 }
- { 1F06 } { 0391 }
- { 1F07 } { 0391 }
- { 1F08 } { 0391 }
- { 1F09 } { 0391 }
- { 1F0A } { 0391 }
- { 1F0B } { 0391 }
- { 1F0C } { 0391 }
- { 1F0D } { 0391 }
- { 1F0E } { 0391 }
- { 1F0F } { 0391 }
- { 1F10 } { 0395 }
- { 1F11 } { 0395 }
- { 1F12 } { 0395 }
- { 1F13 } { 0395 }
- { 1F14 } { 0395 }
- { 1F15 } { 0395 }
- { 1F18 } { 0395 }
- { 1F19 } { 0395 }
- { 1F1A } { 0395 }
- { 1F1B } { 0395 }
- { 1F1C } { 0395 }
- { 1F1D } { 0395 }
- { 1F20 } { 0397 }
- { 1F21 } { 0397 }
- { 1F22 } { 0397 }
- { 1F23 } { 0397 }
- { 1F24 } { 0397 }
- { 1F25 } { 0397 }
- { 1F26 } { 0397 }
- { 1F27 } { 0397 }
- { 1F28 } { 0397 }
- { 1F29 } { 0397 }
- { 1F2A } { 0397 }
- { 1F2B } { 0397 }
- { 1F2C } { 0397 }
- { 1F2D } { 0397 }
- { 1F2E } { 0397 }
- { 1F2F } { 0397 }
- { 1F30 } { 0399 }
- { 1F31 } { 0399 }
- { 1F32 } { 0399 }
- { 1F33 } { 0399 }
- { 1F34 } { 0399 }
- { 1F35 } { 0399 }
- { 1F36 } { 0399 }
- { 1F37 } { 0399 }
- { 1F38 } { 0399 }
- { 1F39 } { 0399 }
- { 1F3A } { 0399 }
- { 1F3B } { 0399 }
- { 1F3C } { 0399 }
- { 1F3D } { 0399 }
- { 1F3E } { 0399 }
- { 1F3F } { 0399 }
- { 1F40 } { 039F }
- { 1F41 } { 039F }
- { 1F42 } { 039F }
- { 1F43 } { 039F }
- { 1F44 } { 039F }
- { 1F45 } { 039F }
- { 1F48 } { 039F }
- { 1F49 } { 039F }
- { 1F4A } { 039F }
- { 1F4B } { 039F }
- { 1F4C } { 039F }
- { 1F4D } { 039F }
- { 1F50 } { 03A5 }
- { 1F51 } { 03A5 }
- { 1F52 } { 03A5 }
- { 1F53 } { 03A5 }
- { 1F54 } { 03A5 }
- { 1F55 } { 03A5 }
- { 1F56 } { 03A5 }
- { 1F57 } { 03A5 }
- { 1F59 } { 03A5 }
- { 1F5B } { 03A5 }
- { 1F5D } { 03A5 }
- { 1F5F } { 03A5 }
- { 1F60 } { 03A9 }
- { 1F61 } { 03A9 }
- { 1F62 } { 03A9 }
- { 1F63 } { 03A9 }
- { 1F64 } { 03A9 }
- { 1F65 } { 03A9 }
- { 1F66 } { 03A9 }
- { 1F67 } { 03A9 }
- { 1F68 } { 03A9 }
- { 1F69 } { 03A9 }
- { 1F6A } { 03A9 }
- { 1F6B } { 03A9 }
- { 1F6C } { 03A9 }
- { 1F6D } { 03A9 }
- { 1F6E } { 03A9 }
- { 1F6F } { 03A9 }
- { 1F70 } { 0391 }
- { 1F71 } { 0391 }
- { 1F72 } { 0395 }
- { 1F73 } { 0395 }
- { 1F74 } { 0397 }
- { 1F75 } { 0397 }
- { 1F76 } { 0399 }
- { 1F77 } { 0399 }
- { 1F78 } { 039F }
- { 1F79 } { 039F }
- { 1F7A } { 03A5 }
- { 1F7B } { 03A5 }
- { 1F7C } { 03A9 }
- { 1F7D } { 03A9 }
- { 1F80 } { 1FBC }
- { 1F81 } { 1FBC }
- { 1F82 } { 1FBC }
- { 1F83 } { 1FBC }
- { 1F84 } { 1FBC }
- { 1F85 } { 1FBC }
- { 1F86 } { 1FBC }
- { 1F87 } { 1FBC }
- { 1F88 } { 1FBC }
- { 1F89 } { 1FBC }
- { 1F8A } { 1FBC }
- { 1F8B } { 1FBC }
- { 1F8C } { 1FBC }
- { 1F8D } { 1FBC }
- { 1F8E } { 1FBC }
- { 1F8F } { 1FBC }
- { 1F90 } { 1FCC }
- { 1F91 } { 1FCC }
- { 1F92 } { 1FCC }
- { 1F93 } { 1FCC }
- { 1F94 } { 1FCC }
- { 1F95 } { 1FCC }
- { 1F96 } { 1FCC }
- { 1F97 } { 1FCC }
- { 1F98 } { 1FCC }
- { 1F99 } { 1FCC }
- { 1F9A } { 1FCC }
- { 1F9B } { 1FCC }
- { 1F9C } { 1FCC }
- { 1F9D } { 1FCC }
- { 1F9E } { 1FCC }
- { 1F9F } { 1FCC }
- { 1FA0 } { 1FFC }
- { 1FA1 } { 1FFC }
- { 1FA2 } { 1FFC }
- { 1FA3 } { 1FFC }
- { 1FA4 } { 1FFC }
- { 1FA5 } { 1FFC }
- { 1FA6 } { 1FFC }
- { 1FA7 } { 1FFC }
- { 1FA8 } { 1FFC }
- { 1FA9 } { 1FFC }
- { 1FAA } { 1FFC }
- { 1FAB } { 1FFC }
- { 1FAC } { 1FFC }
- { 1FAD } { 1FFC }
- { 1FAE } { 1FFC }
- { 1FAF } { 1FFC }
- { 1FB0 } { 1FB8 }
- { 1FB1 } { 1FB9 }
- { 1FB2 } { 1FBC }
- { 1FB3 } { 1FBC }
- { 1FB4 } { 1FBC }
- { 1FB6 } { 0391 }
- { 1FB7 } { 1FBC }
- { 1FB8 } { 1FB8 }
- { 1FB9 } { 1FB9 }
- { 1FBA } { 0391 }
- { 1FBB } { 0391 }
- { 1FBC } { 1FBC }
- { 1FBD } { 1FBD }
- { 1FC2 } { 1FCC }
- { 1FC3 } { 1FCC }
- { 1FC4 } { 1FCC }
- { 1FC6 } { 0397 }
- { 1FC7 } { 1FCC }
- { 1FC8 } { 0395 }
- { 1FC9 } { 0395 }
- { 1FCA } { 0397 }
- { 1FCB } { 0397 }
- { 1FCC } { 1FCC }
- { 1FD0 } { 1FD8 }
- { 1FD1 } { 1FD9 }
- { 1FD2 } { 03AA }
- { 1FD3 } { 03AA }
- { 1FD6 } { 0399 }
- { 1FD7 } { 03AA }
- { 1FD8 } { 1FD8 }
- { 1FD9 } { 1FD9 }
- { 1FDA } { 0399 }
- { 1FDB } { 0399 }
- { 1FE0 } { 1FE8 }
- { 1FE1 } { 1FE9 }
- { 1FE2 } { 03AB }
- { 1FE3 } { 03AB }
- { 1FE4 } { 03A1 }
- { 1FE5 } { 03A1 }
- { 1FE6 } { 03A5 }
- { 1FE7 } { 03AB }
- { 1FE8 } { 1FE8 }
- { 1FE9 } { 1FE9 }
- { 1FEA } { 03A5 }
- { 1FEB } { 03A5 }
- { 1FEC } { 1FEC }
- { 1FF2 } { 1FFC }
- { 1FF3 } { 1FFC }
- { 1FF4 } { 1FFC }
- { 1FF6 } { 03A9 }
- { 1FF7 } { 1FFC }
- { 1FF8 } { 039F }
- { 1FF9 } { 039F }
- { 1FFA } { 03A9 }
- { 1FFB } { 03A9 }
- { 1FFC } { 1FFC }
- \q_recursion_tail ?
- \q_recursion_stop
- }
-\group_end:
-% \end{macrocode}
-%
% The (fixed) look-up mappings for letter-like control sequences.
% \begin{macrocode}
\group_begin:
diff --git a/macros/latex/contrib/l3kernel/l3text-map.dtx b/macros/latex/contrib/l3kernel/l3text-map.dtx
index 66e8e15d8a..850ca94184 100644
--- a/macros/latex/contrib/l3kernel/l3text-map.dtx
+++ b/macros/latex/contrib/l3kernel/l3text-map.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3text-purify.dtx b/macros/latex/contrib/l3kernel/l3text-purify.dtx
index 8ceaa1bdc2..795e2d1524 100644
--- a/macros/latex/contrib/l3kernel/l3text-purify.dtx
+++ b/macros/latex/contrib/l3kernel/l3text-purify.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -486,7 +486,7 @@
\text_declare_purify_equivalent:Nx #1
{
\exp_args:Ne \@@_tmp:n
- { \char_to_utfviii_bytes:n { "#2 } }
+ { \__kernel_codepoint_to_bytes:n { "#2 } }
}
\@@_loop:Nn
}
@@ -574,7 +574,7 @@
\cs_set:Npn \@@_tmp:n #1
{
\exp_args:Ne \@@_tmp_aux:n
- { \char_to_utfviii_bytes:n { "#1 } }
+ { \__kernel_codepoint_to_bytes:n { "#1 } }
}
\cs_set:Npn \@@_tmp_aux:n #1 { \@@_tmp:nnnn #1 }
\cs_set:Npn \@@_tmp:nnnn #1#2#3#4
diff --git a/macros/latex/contrib/l3kernel/l3text.dtx b/macros/latex/contrib/l3kernel/l3text.dtx
index 075a1d014b..0f7cad031f 100644
--- a/macros/latex/contrib/l3kernel/l3text.dtx
+++ b/macros/latex/contrib/l3kernel/l3text.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -89,7 +89,7 @@
%
% \section{Case changing}
%
-% \begin{function}[EXP, added = 2019-11-20, updated = 2020-02-24]
+% \begin{function}[EXP, added = 2019-11-20, updated = 2022-10-13]
% {
% \text_lowercase:n, \text_uppercase:n, \text_titlecase:n,
% \text_titlecase_first:n,
@@ -103,8 +103,9 @@
% Takes user input \meta{text} first applies \cs{text_expand}, then
% transforms the case of character tokens as specified by the
% function name. The category code of letters are not changed by this
-% process (at least where they can be represented by the engine as a single
-% token: $8$-bit engines may require active characters).
+% process when Unicode engines are used; in $8$-bit engines, case changed
+% charters in the ASCII range will have the current prevailing category code,
+% while those outside of it will be represented by active characters.
% \end{function}
%
% Upper- and lowercase have the obvious meanings. Titlecasing may be regarded
@@ -118,7 +119,7 @@
% Importantly, notice that these functions are intended for working with
% user \emph{text for typesetting}. For case changing programmatic data see
% the \pkg{l3str} module and discussion there of \cs{str_lowercase:n},
-% \cs{str_uppercase:n} and \cs{str_foldcase:n}.
+% \cs{str_uppercase:n} and \cs{str_casefold:n}.
%
% Case changing does not take place within math mode material so for example
% \begin{verbatim}
@@ -129,22 +130,15 @@
% SOME TEXT $y = mx + c$ WITH {BRACES}
% \end{verbatim}
%
-% The first maandatory argument of commands listed in
+% The first mandatory argument of commands listed in
% \cs{l_text_case_exclude_arg_tl}
% is excluded from case changing; the latter are entirely non-textual
% content (such as labels).
%
-% As is generally true for \pkg{expl3}, these functions are designed to
-% work with Unicode input only. As such, UTF-8 input is assumed for
-% \emph{all} engines. When used with \XeTeX{} or \LuaTeX{} a full range of
-% Unicode transformations are enabled. Specifically, the standard mappings
+% The standard mappings
% here follow those defined by the \href{http://www.unicode.org}^^A
% {Unicode Consortium} in \texttt{UnicodeData.txt} and
-% \texttt{SpecialCasing.txt}. In the case of $8$-bit engines, mappings
-% are provided for characters which can be represented in output typeset
-% using the |T1|, |T2| and |LGR| font encodings.
-% Thus for example \texttt{ä} can be
-% case-changed using \pdfTeX{}. For \pTeX{} only the ASCII range is
+% \texttt{SpecialCasing.txt}. For \pTeX{}, only the ASCII range is
% covered as the engine treats input outside of this range as east Asian.
%
% Language-sensitive conversions are enabled using the \meta{language}
@@ -173,9 +167,7 @@
% leaves accents in place. A variant \texttt{el-x-iota} is available
% which retains the \textit{ypogegrammeni} (subscript muted iota)
% when uppercasing: the standard version converts these to a following
-% capital iota. For $8$-bit engines a simplified approach is taken
-% which will remove accents when uppercasing but without full
-% context analysis.
+% capital iota.
% \item Lithuanian (\texttt{lt}).
% The lowercase letters i and j should retain a dot above when the
% accents grave, acute or tilde are present. This is implemented for
@@ -677,10 +669,26 @@
}
\cs_new:Npn \@@_codepoint_process:nNN #1#2#3
{ #1 {#2#3} }
- \cs_new:Npn \@@_codepoint_process:nNNN #1#2#3#4
- { #1 {#2#3#4} }
- \cs_new:Npn \@@_codepoint_process:nNNNN #1#2#3#4#5
- { #1 {#2#3#4#5} }
+ \sys_if_engine_ptex:TF
+ {
+ \cs_gset:Npn \@@_codepoint_process:nN #1#2
+ {
+ \int_compare:nNnTF { `#2 } > { "80 }
+ {
+ \int_compare:nNnTF { `#2 } < { "E0 }
+ { \@@_codepoint_process:nNN }
+ { \use:n }
+ }
+ { \use:n }
+ {#1} #2
+ }
+ }
+ {
+ \cs_new:Npn \@@_codepoint_process:nNNN #1#2#3#4
+ { #1 {#2#3#4} }
+ \cs_new:Npn \@@_codepoint_process:nNNNN #1#2#3#4#5
+ { #1 {#2#3#4#5} }
+ }
}
% \end{macrocode}
% \end{macro}
@@ -689,10 +697,11 @@
% \end{macro}
%
% \begin{macro}[EXP, pTF]{\@@_codepoint_compare:nNn}
-% \begin{macro}[EXP]{\@@_codepoint_compare:N, \@@_codepoint_compare_aux:N}
-% \begin{macro}[EXP]{\@@_codepoint_compare:NN}
-% \begin{macro}[EXP]{\@@_codepoint_compare:NNN}
-% \begin{macro}[EXP]{\@@_codepoint_compare:NNNN}
+% \begin{macro}[EXP]{\@@_codepoint_from_chars:Nw}
+% \begin{macro}[EXP]{\@@_codepoint_from_chars:N}
+% \begin{macro}[EXP]{\@@_codepoint_from_chars:NN}
+% \begin{macro}[EXP]{\@@_codepoint_from_chars:NNN}
+% \begin{macro}[EXP]{\@@_codepoint_from_chars:NNNN}
% Allows comparison for all engines using a first \enquote{character} followed
% by a codepoint.
% \begin{macrocode}
@@ -703,51 +712,75 @@
\prg_new_conditional:Npnn
\@@_codepoint_compare:nNn #1#2#3 { TF , p }
{
- \int_compare:nNnTF { `#1 } #2 {#3}
+ \int_compare:nNnTF {`#1} #2 {#3}
\prg_return_true: \prg_return_false:
}
+ \cs_new:Npn \@@_codepoint_from_chars:Nw #1 {`#1}
}
{
\prg_new_conditional:Npnn
\@@_codepoint_compare:nNn #1#2#3 { TF , p }
{
- \int_compare:nNnTF { \@@_codepoint_compare:N #1 }
+ \int_compare:nNnTF { \@@_codepoint_from_chars:Nw #1 }
#2 {#3}
\prg_return_true: \prg_return_false:
}
- \cs_new:Npn \@@_codepoint_compare:N #1
+ \cs_new:Npn \@@_codepoint_from_chars:Nw #1
{
\if_int_compare:w `#1 > "80 \exp_stop_f:
\if_int_compare:w `#1 < "E0 \exp_stop_f:
\exp_after:wN \exp_after:wN \exp_after:wN
- \@@_codepoint_compare:NN
+ \@@_codepoint_from_chars:NN
\else:
\if_int_compare:w `#1 < "F0 \exp_stop_f:
\exp_after:wN \exp_after:wN \exp_after:wN
\exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_codepoint_compare:NNN
+ \exp_after:wN \@@_codepoint_from_chars:NNN
\else:
\exp_after:wN \exp_after:wN \exp_after:wN
\exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_codepoint_compare:NNNN
+ \exp_after:wN \@@_codepoint_from_chars:NNNN
\fi:
\fi:
\else:
- \exp_after:wN \@@_codepoint_compare_aux:N
+ \exp_after:wN \@@_codepoint_from_chars:N
\fi:
#1
}
- \cs_new:Npn \@@_codepoint_compare_aux:N #1 { `#1 }
- \cs_new:Npn \@@_codepoint_compare:NN #1#2
+ \cs_new:Npn \@@_codepoint_from_chars:N #1 { `#1 }
+ \cs_new:Npn \@@_codepoint_from_chars:NN #1#2
{ (`#1 - "C0) * "40 + `#2 - "80 }
- \cs_new:Npn \@@_codepoint_compare:NNN #1#2#3
- { (`#1 - "E0) * "1000 + (`#2 - "80) * "40 + `#3 - "80 }
- \cs_new:Npn \@@_codepoint_compare:NNNN #1#2#3#4
+ % \end{macrocode}
+ % Avoid high chars with p\TeX{}.
+ % \begin{macrocode}
+ \sys_if_engine_ptex:TF
{
- (`#1 - "F0) * "40000
- + (`#2 - "80) * "1000
- + (`#3 - "80) * "40
- + `#4 - "80
+ \cs_gset:Npn \@@_codepoint_from_chars:Nw #1
+ {
+ \if_int_compare:w `#1 > "80 \exp_stop_f:
+ \if_int_compare:w `#1 < "E0 \exp_stop_f:
+ \exp_after:wN \exp_after:wN \exp_after:wN
+ \@@_codepoint_from_chars:NN
+ \else:
+ \exp_after:wN \exp_after:wN \exp_after:wN
+ \@@_codepoint_from_chars:N
+ \fi:
+ \else:
+ \exp_after:wN \@@_codepoint_from_chars:N
+ \fi:
+ #1
+ }
+ }
+ {
+ \cs_new:Npn \@@_codepoint_from_chars:NNN #1#2#3
+ { (`#1 - "E0) * "1000 + (`#2 - "80) * "40 + `#3 - "80 }
+ \cs_new:Npn \@@_codepoint_from_chars:NNNN #1#2#3#4
+ {
+ (`#1 - "F0) * "40000
+ + (`#2 - "80) * "1000
+ + (`#3 - "80) * "40
+ + `#4 - "80
+ }
}
}
% \end{macrocode}
@@ -756,6 +789,7 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
%
% \subsection{Configuration variables}
%
@@ -793,6 +827,7 @@
{
\exp_not:n { \begin \cite \end \label \ref }
\exp_not:c { cite ~ }
+ \exp_not:n { \babelshorthand }
}
% \end{macrocode}
% \end{variable}
@@ -1144,7 +1179,8 @@
% from handling of legacy input encodings: they need to end up in a
% representation we can deal with in further processing. The tests for
% explicit parts of the \LaTeXe{} UTF-8 mechanism cover the case of
-% bookmarks, where definitions change and are no longer protected.
+% bookmarks, where definitions change and are no longer protected. The
+% same is true for \pkg{babel} shorthands.
% \begin{macrocode}
\cs_new:Npn \@@_expand_explicit:N #1
{
@@ -1161,6 +1197,7 @@
{ \tl_if_head_eq_meaning_p:oN {#1} \UTFviii@two@octets }
{ \tl_if_head_eq_meaning_p:oN {#1} \UTFviii@three@octets }
{ \tl_if_head_eq_meaning_p:oN {#1} \UTFviii@four@octets }
+ { \tl_if_head_eq_meaning_p:oN {#1} \active@prefix }
}
}
{ \exp_after:wN \@@_expand_loop:w #1 }
diff --git a/macros/latex/contrib/l3kernel/l3tl-analysis.dtx b/macros/latex/contrib/l3kernel/l3tl-analysis.dtx
index 4cc0ed382c..eee5242eca 100644
--- a/macros/latex/contrib/l3kernel/l3tl-analysis.dtx
+++ b/macros/latex/contrib/l3kernel/l3tl-analysis.dtx
@@ -44,7 +44,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
diff --git a/macros/latex/contrib/l3kernel/l3tl.dtx b/macros/latex/contrib/l3kernel/l3tl.dtx
index 0494e18ae5..6c129ed524 100644
--- a/macros/latex/contrib/l3kernel/l3tl.dtx
+++ b/macros/latex/contrib/l3kernel/l3tl.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -450,7 +450,7 @@
% \end{syntax}
% Tests if the first \meta{token} in the \meta{token list}
% is an explicit space character
-% (explicit token with character code~$12$ and category code~$10$).
+% (explicit token with character code~$32$ and category code~$10$).
% In particular, the test is \texttt{false} if the \meta{token list}
% starts with an implicit token such as \cs{c_space_token}, or if it
% is empty.
diff --git a/macros/latex/contrib/l3kernel/l3token.dtx b/macros/latex/contrib/l3kernel/l3token.dtx
index e8af4d063f..6fa3508c45 100644
--- a/macros/latex/contrib/l3kernel/l3token.dtx
+++ b/macros/latex/contrib/l3kernel/l3token.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
@@ -155,26 +155,6 @@
% \end{texnote}
% \end{function}
%
-% \begin{function}[added = 2020-01-09, EXP]
-% {
-% \char_lowercase:N, \char_uppercase:N,
-% \char_titlecase:N, \char_foldcase:N,
-% \char_str_lowercase:N, \char_str_uppercase:N,
-% \char_str_titlecase:N, \char_str_foldcase:N
-% }
-% \begin{syntax}
-% \cs{char_lowercase:N} \meta{char}
-% \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
-% 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
-% characters with the category code of the \meta{char} (i.e.~only
-% the character code changes).
-% \end{function}
-%
% \begin{variable}[added = 2011-09-05]{\c_catcode_other_space_tl}
% Token list containing one character with category code $12$,
% (\enquote{other}), and character code $32$ (space).
@@ -1222,6 +1202,28 @@
% characters at the start of the argument are \emph{not} ignored in this
% case (and they prevent brace-stripping).
%
+% \section{Deprecated functions}
+%
+% \begin{function}[added = 2020-01-09, EXP]
+% {
+% \char_lowercase:N, \char_uppercase:N,
+% \char_titlecase:N, \char_foldcase:N,
+% \char_str_lowercase:N, \char_str_uppercase:N,
+% \char_str_titlecase:N, \char_str_foldcase:N
+% }
+% \begin{syntax}
+% \cs{char_lowercase:N} \meta{char}
+% \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
+% 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
+% characters with the category code of the \meta{char} (i.e.~only
+% the character code changes).
+% \end{function}
+%
% \end{documentation}
%
% \begin{implementation}
@@ -1690,304 +1692,78 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP]{\char_to_utfviii_bytes:n}
-% \begin{macro}[EXP]{\@@_to_utfviii_bytes_auxi:n}
-% \begin{macro}[EXP]{\@@_to_utfviii_bytes_auxii:Nnn}
-% \begin{macro}[EXP]{\@@_to_utfviii_bytes_auxiii:n}
-% \begin{macro}[EXP]
-% {
-% \@@_to_utfviii_bytes_outputi:nw ,
-% \@@_to_utfviii_bytes_outputii:nw ,
-% \@@_to_utfviii_bytes_outputiii:nw ,
-% \@@_to_utfviii_bytes_outputiv:nw
-% }
-% \begin{macro}[EXP]
-% {\@@_to_utfviii_bytes_output:nnn, \@@_to_utfviii_bytes_output:fnn}
-% \begin{macro}[EXP]{\@@_to_utfviii_bytes_end:}
-% This code converts a codepoint into the correct UTF-8 representation.
-% In terms of the algorithm itself, see
-% \url{https://en.wikipedia.org/wiki/UTF-8} for the octet pattern.
-% \begin{macrocode}
-\cs_new:Npn \char_to_utfviii_bytes:n #1
- {
- \exp_args:Nf \@@_to_utfviii_bytes_auxi:n
- { \int_eval:n {#1} }
- }
-\cs_new:Npn \@@_to_utfviii_bytes_auxi:n #1
- {
- \if_int_compare:w #1 > "80 \exp_stop_f:
- \if_int_compare:w #1 < "800 \exp_stop_f:
- \@@_to_utfviii_bytes_outputi:nw
- { \@@_to_utfviii_bytes_auxii:Nnn C {#1} { 64 } }
- \@@_to_utfviii_bytes_outputii:nw
- { \@@_to_utfviii_bytes_auxiii:n {#1} }
- \else:
- \if_int_compare:w #1 < "10000 \exp_stop_f:
- \@@_to_utfviii_bytes_outputi:nw
- { \@@_to_utfviii_bytes_auxii:Nnn E {#1} { 64 * 64 } }
- \@@_to_utfviii_bytes_outputii:nw
- {
- \@@_to_utfviii_bytes_auxiii:n
- { \int_div_truncate:nn {#1} { 64 } }
- }
- \@@_to_utfviii_bytes_outputiii:nw
- { \@@_to_utfviii_bytes_auxiii:n {#1} }
- \else:
- \@@_to_utfviii_bytes_outputi:nw
- {
- \@@_to_utfviii_bytes_auxii:Nnn F
- {#1} { 64 * 64 * 64 }
- }
- \@@_to_utfviii_bytes_outputii:nw
- {
- \@@_to_utfviii_bytes_auxiii:n
- { \int_div_truncate:nn {#1} { 64 * 64 } }
- }
- \@@_to_utfviii_bytes_outputiii:nw
- {
- \@@_to_utfviii_bytes_auxiii:n
- { \int_div_truncate:nn {#1} { 64 } }
- }
- \@@_to_utfviii_bytes_outputiv:nw
- { \@@_to_utfviii_bytes_auxiii:n {#1} }
- \fi:
- \fi:
- \else:
- \@@_to_utfviii_bytes_outputi:nw {#1}
- \fi:
- \@@_to_utfviii_bytes_end: { } { } { } { }
- }
-\cs_new:Npn \@@_to_utfviii_bytes_auxii:Nnn #1#2#3
- { "#10 + \int_div_truncate:nn {#2} {#3} }
-\cs_new:Npn \@@_to_utfviii_bytes_auxiii:n #1
- { \int_mod:nn {#1} { 64 } + 128 }
-\cs_new:Npn \@@_to_utfviii_bytes_outputi:nw
- #1 #2 \@@_to_utfviii_bytes_end: #3
- { \@@_to_utfviii_bytes_output:fnn { \int_eval:n {#1} } { } {#2} }
-\cs_new:Npn \@@_to_utfviii_bytes_outputii:nw
- #1 #2 \@@_to_utfviii_bytes_end: #3#4
- { \@@_to_utfviii_bytes_output:fnn { \int_eval:n {#1} } { {#3} } {#2} }
-\cs_new:Npn \@@_to_utfviii_bytes_outputiii:nw
- #1 #2 \@@_to_utfviii_bytes_end: #3#4#5
- {
- \@@_to_utfviii_bytes_output:fnn
- { \int_eval:n {#1} } { {#3} {#4} } {#2}
- }
-\cs_new:Npn \@@_to_utfviii_bytes_outputiv:nw
- #1 #2 \@@_to_utfviii_bytes_end: #3#4#5#6
- {
- \@@_to_utfviii_bytes_output:fnn
- { \int_eval:n {#1} } { {#3} {#4} {#5} } {#2}
- }
-\cs_new:Npn \@@_to_utfviii_bytes_output:nnn #1#2#3
- {
- #3
- \@@_to_utfviii_bytes_end: #2 {#1}
- }
-\cs_generate_variant:Nn \@@_to_utfviii_bytes_output:nnn { f }
-\cs_new:Npn \@@_to_utfviii_bytes_end: { }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[rEXP]{\char_to_nfd:N}
-% \begin{macro}[rEXP]{\@@_to_nfd:n, \@@_to_nfd:e}
-% \begin{macro}[rEXP]{\@@_to_nfd:Nw}
-% \begin{macro}[rEXP]{\char_to_nfd:n}
-% \begin{macro}[rEXP]{\char_to_nfd:w}
-% \begin{macro}[rEXP]{\char_nfd_generate:n}
-% \begin{macro}[rEXP]{\char_nfd_generate:nnnn}
-% Look up any \textsc{nfd} and recursively produce the result. Having shared
-% code between Unicode and $8$-bit engines would be ideal, but this would be
-% awkward as we have completely different treatment of catcodes, numbers
-% of tokens, etc. The apparent saving becomes more of a headache than it's
-% worth \dots
-% \begin{macrocode}
-\bool_lazy_or:nnTF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
- {
- \cs_new:Npn \char_to_nfd:N #1
- {
- \cs_if_exist:cTF { c_@@_nfd_ \token_to_str:N #1 _ tl }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN \@@_to_nfd:Nw
- \exp_after:wN \exp_after:wN \exp_after:wN #1
- \cs:w c_@@_nfd_ \token_to_str:N #1 _tl \cs_end:
- \s_@@_stop
- }
- { \exp_not:n {#1} }
- }
- \cs_new_eq:NN \@@_to_nfd:n \char_to_nfd:N
- \cs_generate_variant:Nn \@@_to_nfd:n { e }
- \cs_new:Npn \@@_to_nfd:Nw #1#2#3 \s_@@_stop
- {
- \@@_to_nfd:e
- { \char_generate:nn { `#2 } { \@@_change_case_catcode:N #1 } }
- \tl_if_blank:nF {#3}
- {
- \@@_to_nfd:e
- { \char_generate:nn { `#3 } { \char_value_catcode:n { `#3 } } }
- }
- }
- \cs_new:Npn \char_to_nfd:n #1
- {
- \@@_to_nfd:e { \char_generate:nn {#1} { \char_value_catcode:n {#1} } }
- }
- }
- {
- \cs_new:Npn \char_to_nfd:N #1 { \exp_not:n {#1} }
- \cs_new:Npn \char_to_nfd:n #1
- {
- \int_compare:nNnTF {#1} > { "80 }
- { \exp_args:Ne \@@_to_nfd:n { \@@_nfd_generate:n {#1} } }
- { \@@_nfd_generate:n {#1} }
- }
- \cs_new:Npn \@@_to_nfd:n #1
- {
- \cs_if_exist:cTF { c_@@_nfd_ \tl_to_str:n {#1} _ tl }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN \@@_to_nfd:w
- \cs:w c_@@_nfd_ \tl_to_str:n {#1} _tl \cs_end:
- \s_@@_stop
- }
- { \exp_not:n {#1} }
- }
- \cs_new:Npn \@@_to_nfd:w #1#2 \s_@@_stop
- {
- \@@_to_nfd:n {#1}
- \tl_if_blank:nF {#2}
- { \@@_to_nfd:n {#2} }
- }
- \cs_new:Npn \@@_nfd_generate:n #1
- {
- \use:e
- {
- \exp_not:N \@@_nfd_generate:nnnn
- \char_to_utfviii_bytes:n {#1}
- }
- }
- \cs_new:Npn \@@_nfd_generate:nnnn #1#2#3#4
- {
- \tl_if_blank:nTF {#2}
- { \char_generate:nn {#1} { \char_value_catcode:n {#1} } }
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#1} { 13 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#2} { 13 }
- \tl_if_blank:nF {#3}
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#3} { 13 }
- \tl_if_blank:nF {#4}
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_not:N \char_generate:nn {#4} { 13 }
- }
- }
- }
-
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
% \begin{macro}[EXP]
% {
% \char_lowercase:N, \char_uppercase:N,
% \char_titlecase:N, \char_foldcase:N
% }
-% \begin{macro}[EXP]{\@@_change_case:nNN}
% \begin{macro}[EXP]{\@@_change_case:nN}
-% \begin{macro}[EXP]{\@@_change_case_multi:nN, \@@_change_case_multi:vN}
-% \begin{macro}[EXP]{\@@_change_case_multi:NNNNw}
-% \begin{macro}[EXP]{\@@_change_case:NNN}
-% \begin{macro}[EXP]{\@@_change_case:NNNN}
-% \begin{macro}[EXP]{\@@_change_case:NN}
+% \begin{macro}[EXP]{\@@_change_case:nnnN}
+% \begin{macro}[EXP]{\@@_change_case_auxi:nN, \@@_change_case_auxii:nN}
% \begin{macro}[EXP]{\@@_change_case_catcode:N}
% \begin{macro}[EXP]
% {
% \char_str_lowercase:N, \char_str_uppercase:N,
% \char_str_titlecase:N, \char_str_foldcase:N
% }
-% \begin{macro}[EXP]{\@@_str_change_case:nNN}
-% \begin{macro}[EXP]{\@@_str_change_case:nN}
+% \begin{macro}[EXP]{\@@_str_change_case:nN, \@@_str_change_case_aux:nN}
+% \begin{macro}[EXP]{\@@_str_change_case:nnnN}
+% \begin{macro}[EXP]{\@@_str_change_case:n}
% To ensure that the category codes produced are predictable, every character
-% is re-generated even if it is otherwise unchanged. This makes life a little
-% interesting when we might have multiple output characters: we have to
-% grab each of them and case change them in reverse order to maintain
-% \texttt{f}-type expandability.
-% \begin{macrocode}
-\cs_new:Npn \char_lowercase:N #1
- { \@@_change_case:nNN { lower } \char_value_lccode:n #1 }
-\cs_new:Npn \char_uppercase:N #1
- { \@@_change_case:nNN { upper } \char_value_uccode:n #1 }
-\cs_new:Npn \char_titlecase:N #1
+% is re-generated even if it is otherwise unchanged.
+% \begin{macrocode}
+\cs_new:Npn \char_lowercase:N
+ { \@@_change_case:nN { lowercase } }
+\cs_new:Npn \char_uppercase:N
+ { \@@_change_case:nN { uppercase } }
+\cs_new:Npn \char_titlecase:N
+ { \@@_change_case:nN { titlecase } }
+\cs_new:Npn \char_foldcase:N
+ { \@@_change_case:nN { casefold } }
+\cs_new:Npn \@@_change_case:nN #1#2
{
- \tl_if_exist:cTF { c_@@_titlecase_ \token_to_str:N #1 _tl }
+ \int_compare:nNnTF {`#2} = { `\ }
+ { ~ }
{
- \@@_change_case_multi:vN
- { c_@@_titlecase_ \token_to_str:N #1 _tl } #1
+ \exp_args:Ne \@@_change_case_auxi:nN
+ { \__kernel_codepoint_case:nn {#1} {`#2} } #2
}
- { \char_uppercase:N #1 }
}
-\cs_new:Npn \char_foldcase:N #1
- { \@@_change_case:nNN { fold } \char_value_lccode:n #1 }
-\cs_new:Npn \@@_change_case:nNN #1#2#3
+\cs_new:Npn \@@_change_case_auxi:nN #1#2
+ { \use:e { \@@_change_case:nnnN #1 #2 } }
+\cs_new:Npn \@@_change_case:nnnN #1#2#3#4
{
- \tl_if_exist:cTF { c_@@_ #1 case_ \token_to_str:N #3 _tl }
+ \int_compare:nNnTF {#1} = {`#4}
+ { \exp_not:n {#4} }
{
- \@@_change_case_multi:vN
- { c_@@_ #1 case_ \token_to_str:N #3 _tl } #3
+ \@@_change_case_auxii:nN {#1} {#4}
+ \tl_if_blank:nF {#2}
+ {
+ \@@_change_case_auxii:nN {#2} {#4}
+ \tl_if_blank:nF {#3}
+ { \@@_change_case_auxii:nN {#3} {#4} }
+ }
}
- { \exp_args:Nf \@@_change_case:nN { #2 { `#3 } } #3 }
}
-\cs_new:Npn \@@_change_case:nN #1#2
+\cs_new:Npn \@@_change_case_auxii:nN #1#2
{
- \int_compare:nNnTF {#1} = 0
- { #2 }
- { \char_generate:nn {#1} { \@@_change_case_catcode:N #2 } }
+ \char_generate:nn {#1}
+ { \@@_change_case_catcode:N #2 }
}
-\cs_new:Npn \@@_change_case_multi:nN #1#2
- { \@@_change_case_multi:NNNNw #2 #1 \q_@@_no_value \q_@@_no_value \s_@@_stop }
-\cs_generate_variant:Nn \@@_change_case_multi:nN { v }
-\cs_new:Npn \@@_change_case_multi:NNNNw #1#2#3#4#5 \s_@@_stop
+\bool_lazy_or:nnF
+ { \sys_if_engine_luatex_p: }
+ { \sys_if_engine_xetex_p: }
{
- \@@_quark_if_no_value:NTF #4
+ \cs_gset:Npn \@@_change_case_auxii:nN #1#2
{
- \@@_quark_if_no_value:NTF #3
- { \@@_change_case:NN #1 #2 }
- { \@@_change_case:NNN #1 #2#3 }
+ \int_compare:nNnTF {#1} < { "80 }
+ {
+ \char_generate:nn {#1}
+ { \@@_change_case_catcode:N #2 }
+ }
+ { \exp_not:n {#2} }
}
- { \@@_change_case:NNNN #1 #2#3#4 }
}
-\cs_new:Npn \@@_change_case:NNN #1#2#3
- {
- \exp_args:Nnf \use:nn
- { \@@_change_case:NN #1 #2 }
- { \@@_change_case:NN #1 #3 }
- }
-\cs_new:Npn \@@_change_case:NNNN #1#2#3#4
- {
- \exp_args:Nnff \use:nnn
- { \@@_change_case:NN #1 #2 }
- { \@@_change_case:NN #1 #3 }
- { \@@_change_case:NN #1 #4 }
- }
-\cs_new:Npn \@@_change_case:NN #1#2
- { \char_generate:nn { `#2 } { \@@_change_case_catcode:N #1 } }
\cs_new:Npn \@@_change_case_catcode:N #1
{
\if_catcode:w \exp_not:N #1 \c_math_toggle_token
@@ -2022,47 +1798,43 @@
}
% \end{macrocode}
% Same story for the string version, except category code is easier
-% to follow. This of course makes this version significantly faster.
-% \begin{macrocode}
-\cs_new:Npn \char_str_lowercase:N #1
- { \@@_str_change_case:nNN { lower } \char_value_lccode:n #1 }
-\cs_new:Npn \char_str_uppercase:N #1
- { \@@_str_change_case:nNN { upper } \char_value_uccode:n #1 }
-\cs_new:Npn \char_str_titlecase:N #1
- {
- \tl_if_exist:cTF { c_@@_titlecase_ \token_to_str:N #1 _tl }
- { \tl_to_str:c { c_@@_titlecase_ \token_to_str:N #1 _tl } }
- { \char_str_uppercase:N #1 }
- }
-\cs_new:Npn \char_str_foldcase:N #1
- { \@@_str_change_case:nNN { fold } \char_value_lccode:n #1 }
-\cs_new:Npn \@@_str_change_case:nNN #1#2#3
- {
- \tl_if_exist:cTF { c_@@_ #1 case_ \token_to_str:N #3 _tl }
- { \tl_to_str:c { c_@@_ #1 case_ \token_to_str:N #3 _tl } }
- { \exp_args:Nf \@@_str_change_case:nN { #2 { `#3 } } #3 }
- }
+% to follow. This of course makes this version faster.
+% \begin{macrocode}
+\cs_new:Npn \char_str_lowercase:N
+ { \@@_str_change_case:nN { lowercase } }
+\cs_new:Npn \char_str_uppercase:N
+ { \@@_str_change_case:nN { uppercase } }
+\cs_new:Npn \char_str_titlecase:N
+ { \@@_str_change_case:nN { titlecase } }
+\cs_new:Npn \char_str_foldcase:N
+ { \@@_str_change_case:nN { casefold } }
\cs_new:Npn \@@_str_change_case:nN #1#2
{
- \int_compare:nNnTF {#1} = 0
- { \tl_to_str:n {#2} }
- { \char_generate:nn {#1} { 12 } }
+ \int_compare:nNnTF {`#2} = { `\ }
+ { ~ }
+ {
+ \exp_args:Ne \@@_str_change_case_aux:nN
+ { \__kernel_codepoint_case:nn {#1} {`#2} } #2
+ }
}
-\bool_lazy_or:nnF
- { \cs_if_exist_p:N \tex_luatexversion:D }
- { \cs_if_exist_p:N \tex_XeTeXversion:D }
+\cs_new:Npn \@@_str_change_case_aux:nN #1#2
+ { \use:e { \@@_str_change_case:nnnN #1 #2 } }
+\cs_new:Npn \@@_str_change_case:nnnN #1#2#3#4
{
- \cs_set:Npn \@@_str_change_case:nN #1#2
+ \int_compare:nNnTF {#1} = {`#4}
+ { \tl_to_str:n {#4} }
{
- \int_compare:nNnTF {#1} = 0
- { \tl_to_str:n {#2} }
+ \@@_str_change_case:n {#1}
+ \tl_if_blank:nF {#2}
{
- \int_compare:nTF { `A <= #1 <= `z }
- { \char_generate:nn {#1} { 12 } }
- { \tl_to_str:n {#2} }
+ \@@_str_change_case:n {#2}
+ \tl_if_blank:nF {#3}
+ { \@@_str_change_case:n {#3} }
}
}
}
+\cs_new:Npn \@@_str_change_case:n #1
+ { \char_generate:nn {#1} { 12 } }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -2073,9 +1845,6 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
%
% \begin{macro}{\c_catcode_other_space_tl}
% Create a space with category code $12$: an \enquote{other} space.
diff --git a/macros/latex/contrib/l3kernel/l3unicode.dtx b/macros/latex/contrib/l3kernel/l3unicode.dtx
index 95f410bc1e..66c1ef70ab 100644
--- a/macros/latex/contrib/l3kernel/l3unicode.dtx
+++ b/macros/latex/contrib/l3kernel/l3unicode.dtx
@@ -43,15 +43,72 @@
% }^^A
% }
%
-% \date{Released 2022-11-02}
+% \date{Released 2022-12-17}
%
% \maketitle
%
% \begin{documentation}
%
% This module provides Unicode-specific functions along with loading data
-% from a range of Unicode Consortium files. At present, it provides no
-% public functions.
+% from a range of Unicode Consortium files. Most of the code here is
+% internal, but there are a small set of public functions. These work with
+% Unicode \meta{codepoints} and are designed to give useable results with
+% both Unicode-aware and $8$-bit engines.
+%
+% \begin{function}[EXP, added = 2022-10-09, updated = 2022-11-09]
+% {\codepoint_generate:nn}
+% \begin{syntax}
+% \cs{codepoint_generate:nn} \Arg{codepoint} \Arg{catcode}
+% \end{syntax}
+% Generates one or more character tokens representing the \meta{codepoint}.
+% With Unicode engines, exactly one character token will be generated, and
+% this will have the \meta{catcode} specified as the second argument:
+% \begin{itemize}
+% \item $1$ (begin group)
+% \item $2$ (end group)
+% \item $3$ (math toggle)
+% \item $4$ (alignment)
+% \item $6$ (parameter)
+% \item $7$ (math superscript)
+% \item $8$ (math subscript)
+% \item $10$ (space)
+% \item $11$ (letter)
+% \item $12$ (other)
+% \item $13$ (active)
+% \end{itemize}
+% For $8$-bit engines, between one and four character tokens will be
+% produced: these will be the bytes of the UTF-8 representation of the
+% \meta{codepoint}. For all codepoints outside of the classical ASCII
+% range, the generated character tokens will be active (category code
+% $13$); for codepoints in the ASCII range, the given \meta{catcode}
+% will be used. To allow the result of this function to be used
+% inside a expansion context, the result is protected by \cs{exp_not:n}.
+% \end{function}
+%
+% \begin{function}[EXP, added = 2022-10-09]
+% {\codepoint_str_generate:n}
+% \begin{syntax}
+% \cs{codepoint_str_generate:n} \Arg{codepoint}
+% \end{syntax}
+% Generates one or more character tokens representing the \meta{codepoint}.
+% With Unicode engines, exactly one character token will be generated.
+% For $8$-bit engines, between one and four character tokens will be
+% produced: these will be the bytes of the UTF-8 representation of the
+% \meta{codepoint}. All of the generated character tokens will be of
+% category code $12$, except any spaces (codepoint $32$), which will be
+% category code $10$.
+% \end{function}
+%
+% \begin{function}[added = 2022-10-09, EXP]{\codepoint_to_nfd:n}
+% \begin{syntax}
+% \cs{codepoint_to_nfd:n} \Arg{codepoint}
+% \end{syntax}
+% Converts the \meta{codepoint} to the Unicode Normalization
+% Form Canonical Decomposition. The generated character(s) will have
+% the current category code as they would if typed in directly for Unicode
+% engines; for $8$-bit engines, active characters are used for all codepoints
+% outside of the ASCII range.
+% \end{function}
%
% \end{documentation}
%
@@ -64,122 +121,585 @@
% \end{macrocode}
%
% \begin{macrocode}
-%<@@=char>
+%<@@=codepoint>
+% \end{macrocode}
+%
+% \subsection{User functions}
+%
+% \begin{macro}[EXP]{\codepoint_str_generate:n}
+% \begin{macro}[EXP]{\@@_str_generate:nnnn}
+% \begin{macro}[EXP]{\codepoint_generate:nn}
+% \begin{macro}[EXP]{\@@_generate:nnnn}
+% \begin{macro}[EXP]{\@@_generate:n}
+% Conversion of a codepoint to a character (Unicode engines) or to one
+% or more bytes ($8$-bit engines) is required. For loading the data,
+% all that is needed is the form which creates strings: these are outside
+% the group as they will also be used when looking up data in the hash
+% table storage at point-of-use. Later, we will also need functions that
+% can generate character tokens for document use: those are defined below,
+% in the data recovery setup.
+% \begin{macrocode}
+\bool_lazy_or:nnTF
+ { \sys_if_engine_luatex_p: }
+ { \sys_if_engine_xetex_p: }
+ {
+ \cs_new:Npn \codepoint_str_generate:n #1
+ {
+ \int_compare:nNnTF {#1} = { `\ }
+ { ~ }
+ { \char_generate:nn {#1} { 12 } }
+ }
+ \cs_new:Npn \codepoint_generate:nn #1#2
+ {
+ \int_compare:nNnTF {#1} = { `\ }
+ { ~ }
+ {
+ \__kernel_exp_not:w \exp_after:wN \exp_after:wN \exp_after:wN
+ { \char_generate:nn {#1} {#2} }
+ }
+ }
+ }
+ {
+ \cs_new:Npn \codepoint_str_generate:n #1
+ {
+ \int_compare:nNnTF {#1} = { `\ }
+ { ~ }
+ {
+ \use:e
+ {
+ \exp_not:N \@@_str_generate:nnnn
+ \__kernel_codepoint_to_bytes:n {#1}
+ }
+ }
+ }
+ \cs_new:Npn \@@_str_generate:nnnn #1#2#3#4
+ {
+ \char_generate:nn {#1} { 12 }
+ \tl_if_blank:nF {#2}
+ {
+ \char_generate:nn {#2} { 12 }
+ \tl_if_blank:nF {#3}
+ {
+ \char_generate:nn {#3} { 12 }
+ \tl_if_blank:nF {#4}
+ { \char_generate:nn {#4} { 12 } }
+ }
+ }
+ }
+ \cs_new:Npn \codepoint_generate:nn #1#2
+ {
+ \int_compare:nNnTF {#1} = { `\ }
+ { ~ }
+ {
+ \int_compare:nNnTF {#1} < { "80 }
+ {
+ \__kernel_exp_not:w \exp_after:wN \exp_after:wN \exp_after:wN
+ { \char_generate:nn {#1} {#2} }
+ }
+ {
+ \use:e
+ {
+ \exp_not:N \@@_generate:nnnn
+ \__kernel_codepoint_to_bytes:n {#1}
+ }
+ }
+ }
+ }
+ \cs_new:Npn \@@_generate:nnnn #1#2#3#4
+ {
+ \__kernel_exp_not:w \exp_after:wN
+ {
+ \tex_expanded:D
+ {
+ \@@_generate:n {#1}
+ \@@_generate:n {#2}
+ \tl_if_blank:nF {#3}
+ {
+ \@@_generate:n {#3}
+ \tl_if_blank:nF {#4}
+ { \@@_generate:n {#4} }
+ }
+ }
+ }
+ }
+ \cs_new:Npn \@@_generate:n #1
+ {
+ \__kernel_exp_not:w \exp_after:wN \exp_after:wN \exp_after:wN
+ { \char_generate:nn {#1} { 13 } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\__kernel_codepoint_to_bytes:n}
+% \begin{macro}[EXP]{\@@_to_bytes_auxi:n}
+% \begin{macro}[EXP]{\@@_to_bytes_auxii:Nnn}
+% \begin{macro}[EXP]{\@@_to_bytes_auxiii:n}
+% \begin{macro}[EXP]
+% {
+% \@@_to_bytes_outputi:nw ,
+% \@@_to_bytes_outputii:nw ,
+% \@@_to_bytes_outputiii:nw ,
+% \@@_to_bytes_outputiv:nw
+% }
+% \begin{macro}[EXP]
+% {\@@_to_bytes_output:nnn, \@@_to_bytes_output:fnn}
+% \begin{macro}[EXP]{\@@_to_bytes_end:}
+% This code converts a codepoint into the correct UTF-8 representation.
+% In terms of the algorithm itself, see
+% \url{https://en.wikipedia.org/wiki/UTF-8} for the octet pattern.
+% \begin{macrocode}
+\cs_new:Npn \__kernel_codepoint_to_bytes:n #1
+ {
+ \exp_args:Nf \@@_to_bytes_auxi:n
+ { \int_eval:n {#1} }
+ }
+\cs_new:Npn \@@_to_bytes_auxi:n #1
+ {
+ \if_int_compare:w #1 > "80 \exp_stop_f:
+ \if_int_compare:w #1 < "800 \exp_stop_f:
+ \@@_to_bytes_outputi:nw
+ { \@@_to_bytes_auxii:Nnn C {#1} { 64 } }
+ \@@_to_bytes_outputii:nw
+ { \@@_to_bytes_auxiii:n {#1} }
+ \else:
+ \if_int_compare:w #1 < "10000 \exp_stop_f:
+ \@@_to_bytes_outputi:nw
+ { \@@_to_bytes_auxii:Nnn E {#1} { 64 * 64 } }
+ \@@_to_bytes_outputii:nw
+ {
+ \@@_to_bytes_auxiii:n
+ { \int_div_truncate:nn {#1} { 64 } }
+ }
+ \@@_to_bytes_outputiii:nw
+ { \@@_to_bytes_auxiii:n {#1} }
+ \else:
+ \@@_to_bytes_outputi:nw
+ {
+ \@@_to_bytes_auxii:Nnn F
+ {#1} { 64 * 64 * 64 }
+ }
+ \@@_to_bytes_outputii:nw
+ {
+ \@@_to_bytes_auxiii:n
+ { \int_div_truncate:nn {#1} { 64 * 64 } }
+ }
+ \@@_to_bytes_outputiii:nw
+ {
+ \@@_to_bytes_auxiii:n
+ { \int_div_truncate:nn {#1} { 64 } }
+ }
+ \@@_to_bytes_outputiv:nw
+ { \@@_to_bytes_auxiii:n {#1} }
+ \fi:
+ \fi:
+ \else:
+ \@@_to_bytes_outputi:nw {#1}
+ \fi:
+ \@@_to_bytes_end: { } { } { } { }
+ }
+\cs_new:Npn \@@_to_bytes_auxii:Nnn #1#2#3
+ { "#10 + \int_div_truncate:nn {#2} {#3} }
+\cs_new:Npn \@@_to_bytes_auxiii:n #1
+ { \int_mod:nn {#1} { 64 } + 128 }
+\cs_new:Npn \@@_to_bytes_outputi:nw
+ #1 #2 \@@_to_bytes_end: #3
+ { \@@_to_bytes_output:fnn { \int_eval:n {#1} } { } {#2} }
+\cs_new:Npn \@@_to_bytes_outputii:nw
+ #1 #2 \@@_to_bytes_end: #3#4
+ { \@@_to_bytes_output:fnn { \int_eval:n {#1} } { {#3} } {#2} }
+\cs_new:Npn \@@_to_bytes_outputiii:nw
+ #1 #2 \@@_to_bytes_end: #3#4#5
+ {
+ \@@_to_bytes_output:fnn
+ { \int_eval:n {#1} } { {#3} {#4} } {#2}
+ }
+\cs_new:Npn \@@_to_bytes_outputiv:nw
+ #1 #2 \@@_to_bytes_end: #3#4#5#6
+ {
+ \@@_to_bytes_output:fnn
+ { \int_eval:n {#1} } { {#3} {#4} {#5} } {#2}
+ }
+\cs_new:Npn \@@_to_bytes_output:nnn #1#2#3
+ {
+ #3
+ \@@_to_bytes_end: #2 {#1}
+ }
+\cs_generate_variant:Nn \@@_to_bytes_output:nnn { f }
+\cs_new:Npn \@@_to_bytes_end: { }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\codepoint_to_nfd:n}
+% \begin{macro}[EXP]{\@@_to_nfd:nn}
+% \begin{macro}[EXP]{\@@_to_nfd:nnn}
+% \begin{macro}[EXP]{\@@_to_nfd:nnnn}
+% \begin{macro}[EXP]{\@@_to_nfd_generate:nn}
+% \begin{macro}[EXP]{\@@_to_nfd_generate:n}
+% \begin{macro}[EXP]{\@@_to_nfd_generate:nnnn}
+% Converted to NFD is a potentially-recursive process: the key is to
+% check if we get the input codepoint back again. As far as possible,
+% we use the same path for all engines.
+% \begin{macrocode}
+\cs_new:Npn \codepoint_to_nfd:n #1
+ { \@@_to_nfd:nn {#1} { \char_value_catcode:n {#1} } }
+\cs_new:Npn \@@_to_nfd:nn #1#2
+ {
+ \exp_args:Ne \@@_to_nfd:nnn
+ { \@@_nfd:n {#1} } {#1} {#2}
+ }
+\cs_new:Npn \@@_to_nfd:nnn #1#2#3 { \@@_to_nfd:nnnn #1 {#2} {#3} }
+\cs_new:Npn \@@_to_nfd:nnnn #1#2#3#4
+ {
+ \int_compare:nNnTF {#1} = {#3}
+ { \codepoint_generate:nn {#1} {#4} }
+ {
+ \@@_to_nfd:nn {#1} {#4}
+ \tl_if_blank:nF {#2}
+ { \@@_to_nfd:nn {#2} {#4} }
+ }
+ }
% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Data loader}
%
% Text operations requires data from the Unicode Consortium. Data read into
% Unicode engine formats is at best a small part of what we need, so there
% is a loader here to set up the appropriate data structures.
%
+% Where we need data for most or all of the Unicode range, we use the two-stage
+% table approach recommended by the Unicode Consortium and demonstrated in a
+% model implementation in Python in
+% \url{https://www.strchr.com/multi-stage_tables}. This approach uses the
+% \texttt{intarray} (\texttt{fontdimen}-based) data type as it is fast for
+% random access and avoids significant hash table usage. In contrast, where
+% only a small subset of codepoints are required, storage as macros is
+% preferable. There is also some consideration of the effort needed to load
+% data: see for example the grapheme breaking information, which would be
+% problematic to convert into a two-stage table but which can be used with
+% reasonable performance in a small number of comma lists (at the cost that
+% breaking at higher codepoint Hangul characters will be slightly slow).
+%
+% \begin{variable}{\c_@@_block_size_int}
+% Choosing the block size for the blocks in the two-stage approach is
+% non-trivial: depending on the data stored, the optimal size for
+% memory usage will vary. At the same time, for us there is also the
+% question of load-time: larger blocks require longer comma lists
+% as intermediates, so are slower. As this is going to be needed
+% to use the data, we set it up outside of the group for clarity.
+% \begin{macrocode}
+\int_const:Nn \c_@@_block_size_int { 64 }
+% \end{macrocode}
+% \end{variable}
+%
+% Parsing the data files can be the same way for all engines, but where they
+% are stored as character tokens, the construction method depends on whether
+% they are Unicode or $8$-bit internally. Parsing is therefore done by common
+% functions, with some data storage using engine-specific auxiliaries.
+%
% As only the data needs to remain at the end of this process, everything
% is set up inside a group. The only thing that is outside is creating a
% stream: they are global anyway and it is best to force a stream for
-% all engines. For performance reasons, some of the code here is very
-% low-level: the material is read during loading \pkg{expl3} in package
-% mode.
-%
-% Parsing the data files can be the same way for all engines, but the detail
-% of data storage varies depending on whether they are Unicode or $8$-bit
-% internally.Parsing is therefore done by common functions, with the data
-% storage usign engine-specific auxiliaries.
-%
-% Conversion of a codepoint to a character (Unicode engines) or to one
-% or more bytes ($8$-bit engines) is required. We might need those to be
-% detokenized: if not, for Unicode engines they have the current category
-% code.
+% all engines.
+%
+% \begin{variable}{\g_@@_data_ior}
% \begin{macrocode}
\ior_new:N \g_@@_data_ior
+% \end{macrocode}
+% \end{variable}
+%
+% We need some setup for the two-part table approach. The number of blocks we
+% need will be variable, but the resulting size of the stage one table
+% is predictable. For performance reasons, we therefore create the stage one
+% tables now so they can be used immediately, and will later rename them as a
+% constant tables. For each two-stage table construction, we need a comma
+% list to hold the partial block and a couple of integers to track where
+% we are up to. To avoid burning registers, the latter are stored in macros
+% and are \enquote{fake} integers. We also avoid any \texttt{new} functions,
+% keeping as much as possible local.
+%
+% As we need both positive and negative values, case data requires one
+% two-stage table for each transformation. In contrasts, general Unicode
+% properties could be stored in one table with appropriate combination rules:
+% that is not done at present but is likely to be added over time. Here, all
+% that is needed is additional entries into the comma-list to create the
+% structures.
+%
+% Notice that in the standard \pkg{expl3} way we are indexes position not
+% offset: that does mean a little work later.
+% \begin{macrocode}
\group_begin:
- \bool_lazy_or:nnTF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
+ \clist_map_inline:nn
+ { uppercase , lowercase }
{
- \cs_set:Npn \@@_generate_other:n #1
- { \tex_detokenize:D \tex_expandafter:D { \tex_Uchar:D #1 } }
- \cs_set:Npn \@@_generate:n #1
+ \cs_set_nopar:cpn { l_@@_ #1 _block_clist } { }
+ \cs_set_nopar:cpn { l_@@_ #1 _block_tl } { 1 }
+ \cs_set_nopar:cpn { l_@@_ #1 _pos_tl } { 0 }
+ \intarray_new:cn { g_@@_ #1 _index_intarray }
+ { \int_div_truncate:nn { "110000 } \c_@@_block_size_int }
+ }
+% \end{macrocode}
+% We need an integer value when matching the current block to those we have
+% already seen, and a way to track codepoints for handling ranges. Again,
+% we avoid using up registers or creating global names.
+% \begin{macrocode}
+ \cs_set_nopar:Npn \l_@@_next_codepoint_fint_tl { 0 }
+ \cs_set_nopar:Npn \l_@@_matched_block_tl { 0 }
+% \end{macrocode}
+% Parse the main Unicode data file and pull out the NFD and case changing
+% data. The NFD data is stored on using the hash table approach and can yield
+% a predictable number of code points: one or two. We also need the case data,
+% which will be modified further below. To allow for finding rangs, the
+% description of the codepoint needs to be carried forward.
+% \begin{macrocode}
+ \cs_set_protected:Npn \@@_data_auxi:w
+ #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ; #8 ; #9 ;
+ {
+ \tl_if_blank:nF {#6}
{
- \tex_unexpanded:D \exp_after:wN
- { \tex_Ucharcat:D #1 ~ \tex_catcode:D #1 ~ }
- }
+ \tl_if_head_eq_charcode:nNF {#6} < % >
+ { \@@_data_auxii:w #1 ; #6 ~ \q_stop }
+ }
+ \@@_data_auxiii:w #1 ; #2 ;
}
+ \cs_set_protected:Npn \@@_data_auxii:w #1 ; #2 ~ #3 \q_stop
{
- \cs_set:Npn \@@_generate_other:n #1
+ \tl_const:cx
+ { c_@@_nfd_ \codepoint_str_generate:n {"#1} _tl }
{
- \tex_detokenize:D \tex_expandafter:D
- { \tex_expanded:D { \@@_generate:n {#1} } }
+ {"#2}
+ { \tl_if_blank:nF {#3} {"#3} }
}
- \cs_set:Npn \@@_generate:n #1
+ }
+% \end{macrocode}
+% The case data is going to be stored as an offset from the parent character,
+% rather than an absolute value. We therefore deal with that plus the situation
+% where a codepoint has no mapping data in oen shot.
+% \begin{macrocode}
+ \cs_set_protected:Npn \@@_data_auxiii:w
+ #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ; #8 ~ \q_stop
+ {
+ \use:e
{
- \use:e
- {
- \exp_not:N \@@_generate:nnnn
- \char_to_utfviii_bytes:n {#1}
- }
+ \@@_data_auxiv:w
+ #1 ; #2 ;
+ \@@_data_offset:nn {#1} {#6} ;
+ \@@_data_offset:nn {#1} {#7} ;
+ #8;
+ }
+ }
+ \cs_set:Npn \@@_data_offset:nn #1#2
+ {
+ \tl_if_blank:nTF {#2}
+ { 0 }
+ { \int_eval:n { "#2 - "#1 } }
+ }
+% \end{macrocode}
+% To deal with ranges, we track the position of the next codepoint expected.
+% If there is a gap, we deal with that separately: it could be a range or
+% an unused part of the Unicode space. As such, we deal with the current
+% codepoint here whether or not there is range to fill in. Upper- and
+% lowercase data go into the two-stage table, any titlecase exception is
+% just stored in a macro. The data for the codepoint is added to the current
+% block, and if that is now complete we move on to save the block. The
+% case exceptions are all stored as codepoints, with a fixed number of
+% balanced text as we know that there are never more than three.
+% \begin{macrocode}
+ \cs_set_protected:Npn \@@_data_auxiv:w #1 ; #2 ; #3 ; #4 ; #5 ;
+ {
+ \int_compare:nNnT {"#1} > \l_@@_next_codepoint_fint_tl
+ {
+ \@@_data_auxvi:nnnw {#1} {#3} {#4}
+ #2 Last> \q_stop
}
- \cs_set:Npn \@@_generate:nnnn #1#2#3#4
+ \@@_add:nn { uppercase } {#3}
+ \@@_add:nn { lowercase } {#4}
+ \int_compare:nNnF {#3} = { \@@_data_offset:nn {#1} {#5} }
+ {
+ \tl_const:cx
+ { c_@@_titlecase_ \codepoint_str_generate:n {"#1} _tl }
+ { {"#5} { } { } }
+ }
+ \tl_set:Nx \l_@@_next_codepoint_fint_tl
+ { \int_eval:n { "#1 + 1 } }
+ }
+ \cs_set_protected:Npn \@@_add:nn #1#2
+ {
+ \clist_put_right:cn { l_@@_ #1 _block_clist } {#2}
+ \int_compare:nNnT { \clist_count:c { l_@@_ #1 _block_clist } }
+ = \c_@@_block_size_int
+ { \@@_save_blocks:nn {#1} { 1 } }
+ }
+% \end{macrocode}
+% Distinguish between a range and a gap, and pass on the appropriate value(s).
+% \begin{macrocode}
+ \cs_set_protected:Npn \@@_data_auxvi:nnnw #1#2#3#4 Last> #5 \q_stop
+ {
+ \tl_if_blank:nTF {#5}
+ {
+ \@@_range:nnn {#1} { uppercase } { 0 }
+ \@@_range:nnn {#1} { lowercase } { 0 }
+ }
+ {
+ \@@_range:nnn {#1} { uppercase } {#2}
+ \@@_range:nnn {#1} { lowercase } {#3}
+ }
+ }
+% \end{macrocode}
+% Calculated the length of the range and the space remaining in the current
+% block.
+% \begin{macrocode}
+ \cs_set_protected:Npn \@@_range:nnn #1
+ {
+ \exp_args:Nf \@@_range_aux:nnn
+ { \int_eval:n { "#1 - \l_@@_next_codepoint_fint_tl } }
+ }
+ \cs_set_protected:Npn \@@_range_aux:nnn #1#2
+ {
+ \exp_args:Nf \@@_range:nnnn
{
- \tex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN
- { \char_generate:nn {#1} { 13 } }
- \tl_if_blank:nF {#2}
+ \int_min:nn
+ {#1}
{
- \tex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN
- { \char_generate:nn {#2} { 13 } }
- \tl_if_blank:nF {#3}
- {
- \tex_unexpanded:D \exp_after:wN \exp_after:wN \exp_after:wN
- { \char_generate:nn {#3} { 13 } }
- \tl_if_blank:nF {#4}
- {
- \tex_unexpanded:D
- \exp_after:wN \exp_after:wN \exp_after:wN
- { \char_generate:nn {#4} { 13 } }
- }
- }
+ \c_@@_block_size_int
+ - \clist_count:c { l_@@_ #2 _block_clist }
}
}
+ {#1} {#2}
}
% \end{macrocode}
-% Parse the main Unicode data file for two things. First, we want the titlecase
-% exceptions: the one-to-one lower- and uppercase mappings it contains are all
-% be covered by the \TeX{} data. Second, we need normalization data: at present,
-% just the canonical \textsc{nfd} mappings. Those all yield either one or two
-% codepoints, so the split is relatively easy.
+% Here we want to do three things: add to and possibly complete the current
+% block, add complete blocks quickly, then finish up the range in a final
+% open block. We need to avoid as far as possible avoid dealing with ever
+% single codepoint, so the middle step is optimised.
% \begin{macrocode}
- \cs_set_protected:Npn \@@_data_auxi:w
- #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ; #8 ; #9 ;
+ \cs_set_protected:Npn \@@_range:nnnn #1#2#3#4
{
- \tl_if_blank:nF {#6}
- {
- \tl_if_head_eq_charcode:nNF {#6} < % >
- { \@@_data_auxii:w #1 ; #6 ~ \q_stop }
+ \prg_replicate:nn {#1}
+ { \clist_put_right:cn { l_@@_ #3 _block_clist } {#4} }
+ \int_compare:nNnT { \clist_count:c { l_@@_ #3 _block_clist } }
+ = \c_@@_block_size_int
+ { \@@_save_blocks:nn {#3} { 1 } }
+ \int_compare:nNnF
+ { \int_div_truncate:nn { #2 - #1 } \c_@@_block_size_int } = 0
+ {
+ \tl_set:cx { l_@@_ #3 _block_clist }
+ {
+ \exp_args:NNe \use:nn \use_none:n
+ { \prg_replicate:nn { \c_@@_block_size_int } { , #4 } }
+ }
+ \@@_save_blocks:nn {#3}
+ { \int_div_truncate:nn { (#2 - #1) } \c_@@_block_size_int }
}
- \@@_data_auxiii:w #1 ;
+ \prg_replicate:nn
+ { \int_mod:nn { #2 - #1 } \c_@@_block_size_int }
+ { \clist_put_right:cx { l_@@_ #3 _block_clist } {#4} }
}
- \cs_set_protected:Npn \@@_data_auxii:w #1 ; #2 ~ #3 \q_stop
+% \end{macrocode}
+% To allow rapid comparison, each completed block is stored locally as a
+% comma list: once all of the blocks have been created, they are converted
+% into an \texttt{intarray} in one step. The aim here is to check the current
+% block against those we've already used, and either match to an existing
+% block or save a new block.
+% \begin{macrocode}
+ \cs_set_protected:Npn \@@_save_blocks:nn #1#2
{
- \tl_const:cx
- { c_@@_nfd_ \@@_generate_other:n { "#1 } _tl }
+ \tl_set_eq:Nc \l_@@_matched_block_tl { l_@@_ #1 _block_tl }
+ \int_step_inline:nn { \tl_use:c { l_@@_ #1 _block_tl } - 1 }
{
- { \@@_generate:n { "#2 } }
+ \tl_if_eq:ccT { l_@@_ #1 _block_clist }
+ { l_@@_ #1 _block_ ##1 _clist }
+ { \tl_set:Nn \l_@@_matched_block_tl {##1} }
+ }
+ \int_compare:nNnT
+ { \tl_use:c { l_@@_ #1 _block_tl } } = \l_@@_matched_block_tl
{
- \tl_if_blank:nF {#3}
- { \@@_generate:n { "#3 } }
- }
+ \clist_set_eq:cc
+ {
+ l_@@_ #1 _block_
+ \tl_use:c { l_@@_ #1 _block_tl } _clist
+ }
+ { l_@@_ #1 _block_clist }
+ \tl_set:cx { l_@@_ #1 _block_tl }
+ { \int_eval:n { \tl_use:c { l_@@_ #1 _block_tl } + 1 } }
+ }
+ \prg_replicate:nn {#2}
+ {
+ \tl_set:cx { l_@@_ #1 _pos_tl }
+ { \int_eval:n { \tl_use:c { l_@@_ #1 _pos_tl } + 1 } }
+ \exp_args:Nc \__kernel_intarray_gset:Nnn
+ { g_@@_ #1 _index_intarray }
+ { \tl_use:c { l_@@_ #1 _pos_tl } }
+ \l_@@_matched_block_tl
+ }
+ \clist_clear:c { l_@@_ #1 _block_clist }
+ }
+% \end{macrocode}
+% Close out the final block, rename the first stage table, then combine all
+% of the block comma-lists into one large second-stage table with offsets.
+% As we use an index not an offet, there is a little back-and-forward to do.
+% \begin{macrocode}
+ \cs_set_protected:Npn \@@_finalise_blocks:
+ {
+ \clist_map_inline:nn { uppercase , lowercase }
+ {
+ \@@_range:nnn { 110000 } {##1} { 0 }
+ \@@_finalise_blocks:n {##1}
}
+ }
+ \cs_set_protected:Npn \@@_finalise_blocks:n #1
+ {
+ \cs_gset_eq:cc { c_@@_ #1 _index_intarray } { g_@@_ #1 _index_intarray }
+ \cs_undefine:c { g_@@_ #1 _index_intarray }
+ \intarray_new:cn { g_@@_ #1 _blocks_intarray }
+ { ( \tl_use:c { l_@@_ #1 _block_tl } - 1 ) * \c_@@_block_size_int }
+ \int_step_inline:nn { \tl_use:c { l_@@_ #1 _block_tl } - 1 }
+ {
+ \exp_args:Nv \@@_finalise_blocks:nnn
+ { l_@@_ #1 _block_ ##1 _clist }
+ {##1} {#1}
+ }
+ \cs_gset_eq:cc { c_@@_ #1 _blocks_intarray }
+ { g_@@_ #1 _blocks_intarray }
+ \cs_undefine:c { g_@@_ #1 _blocks_intarray }
}
- \cs_set_protected:Npn \@@_data_auxiii:w
- #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ~ \q_stop
+ \cs_set_protected:Npn \@@_finalise_blocks:nnn #1#2#3
{
- \cs_set_nopar:Npn \l_@@_tmpa_tl {#7}
- \reverse_if:N \if_meaning:w \l_@@_tmpa_tl \c_empty_tl
- \cs_set_nopar:Npn \l_@@_tmpb_tl {#5}
- \reverse_if:N \if_meaning:w \l_@@_tmpa_tl \l_@@_tmpb_tl
- \tl_const:cx
- { c_@@_titlecase_ \@@_generate_other:n { "#1 } _tl }
- { \@@_generate:n { "#7 } }
- \fi:
- \fi:
+ \exp_args:Nnf \@@_finalise_blocks:nnnw { 1 }
+ { \int_eval:n { ( #2 - 1 ) * \c_@@_block_size_int } }
+ {#3}
+ #1 , \q_recursion_tail , \q_recursion_stop
+ }
+ \cs_set_protected:Npn \@@_finalise_blocks:nnnw #1#2#3#4 ,
+ {
+ \quark_if_recursion_tail_stop:n {#4}
+ \intarray_gset:cnn { g_@@_ #3 _blocks_intarray }
+ { #1 + #2 }
+ {#4}
+ \exp_args:Nf \@@_finalise_blocks:nnnw
+ { \int_eval:n { #1 + 1 } } {#2} {#3}
}
+% \end{macrocode}
+% With the setup done, read the main data file: it's easiest to do that as
+% a token list with spaces retained.
+% \begin{macrocode}
\ior_open:Nn \g_@@_data_ior { UnicodeData.txt }
\group_begin:
\char_set_catcode_space:n { `\ }%
@@ -190,8 +710,48 @@
\fi:
\exp_after:wN \@@_data_auxi:w \l_@@_tmpa_tl \q_stop
}%
+ \@@_finalise_blocks:
\group_end:
+\group_end:
+% \end{macrocode}
+%
+% \begin{macro}[EXP]{\__kernel_codepoint_data:nn}
+% \begin{macro}[EXP]{\@@_data:nnn}
+% Recover data from a two-stage table: entirely generic as this applies to
+% all tables (as we use the same block size for all of them). Notice that
+% as we use indices not offsets we have to shuffle out-by-one issues. This
+% function is needed \emph{before} loading the special casing data, as there
+% we need to be able to check the standard case mappings.
+% \begin{macrocode}
+\cs_new:Npn \__kernel_codepoint_data:nn #1#2
+ {
+ \exp_args:Nf \@@_data:nnn
+ {
+ \int_eval:n
+ {
+ \c_@@_block_size_int *
+ (
+ \intarray_item:cn { c_@@_ #1 _index_intarray }
+ {
+ \int_div_truncate:nn {#2}
+ \c_@@_block_size_int
+ + 1
+ }
+ - 1
+ )
+ }
+ }
+ {#2} {#1}
+ }
+\cs_new:Npn \@@_data:nnn #1#2#3
+ {
+ \intarray_item:cn { c_@@_ #3 _blocks_intarray }
+ { #1 + \int_mod:nn {#2} \c_@@_block_size_int + 1 }
+ }
% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% The other data files all use C-style comments so we have to worry about
% |#| tokens (and reading as strings). The set up for case folding is in two
% parts. For the basic (core) mappings, folding is the same as lower casing in
@@ -199,15 +759,17 @@
% always store the result, splitting up the two or three code points in the input
% as required.
% \begin{macrocode}
+\group_begin:
\ior_open:Nn \g_@@_data_ior { CaseFolding.txt }
\cs_set_protected:Npn \@@_data_auxi:w #1 ;~ #2 ;~ #3 ; #4 \q_stop
{
\if:w \tl_head:n { #2 ? } C
\reverse_if:N \if_int_compare:w
- \char_value_lccode:n {"#1} = "#3 ~
+ \int_eval:n { \__kernel_codepoint_data:nn { lowercase } {"#1} + "#1 }
+ = "#3 ~
\tl_const:cx
- { c_@@_foldcase_ \@@_generate_other:n { "#1 } _tl }
- { \@@_generate:n { "#3 } }
+ { c_@@_casefold_ \codepoint_str_generate:n {"#1} _tl }
+ { {"#3} { } { } }
\fi:
\else:
\if:w \tl_head:n { #2 ? } F
@@ -215,25 +777,17 @@
\fi:
\fi:
}
- \bool_lazy_or:nnF
- { \sys_if_engine_luatex_p: }
- { \sys_if_engine_xetex_p: }
- {
- \cs_set_protected:Npn \@@_data_auxi:w #1 ;~ #2 ;~ #3 ; #4 \q_stop
- {
- \if:w \tl_head:n { #2 ? } F
- \@@_data_auxii:w #1 ~ #3 ~ \q_stop
- \fi:
- }
- }
+% \end{macrocode}
+% Here, |#4| can have have a trailing space, so we tidy up a bit at the cost of
+% speed for these small number of cases it applies to.
+% \begin{macrocode}
\cs_set_protected:Npn \@@_data_auxii:w #1 ~ #2 ~ #3 ~ #4 \q_stop
{
- \tl_const:cx { c_@@_foldcase_ \@@_generate_other:n { "#1 } _tl }
+ \tl_const:cx { c_@@_casefold_ \codepoint_str_generate:n {"#1} _tl }
{
- \@@_generate:n { "#2 }
- \@@_generate:n { "#3 }
- \tl_if_blank:nF {#4}
- { \@@_generate:n { \int_value:w "#4 } }
+ {"#2}
+ {"#3}
+ { \tl_if_blank:nF {#4} { " \int_to_Hex:n {"#4} } }
}
}
\ior_str_map_inline:Nn \g_@@_data_ior
@@ -245,7 +799,7 @@
\ior_close:N \g_@@_data_ior
% \end{macrocode}
% For upper- and lowercasing special situations, there is a bit more to
-% do as we also have title casing to consider, plus we need to stop part-way
+% do as we also have titlecasing to consider, plus we need to stop part-way
% through the file.
% \begin{macrocode}
\ior_open:Nn \g_@@_data_ior { SpecialCasing.txt }
@@ -262,12 +816,11 @@
{
\tl_if_empty:nF {#4}
{
- \tl_const:cx { c_@@_ #2 case_ \@@_generate_other:n { "#1 } _tl }
+ \tl_const:cx { c_@@_ #2 case_ \codepoint_str_generate:n {"#1} _tl }
{
- \@@_generate:n { "#3 }
- \@@_generate:n { "#4 }
- \tl_if_blank:nF {#5}
- { \@@_generate:n { "#5 } }
+ {"#3}
+ {"#4}
+ { \tl_if_blank:nF {#5} {"#5} }
}
}
}
@@ -284,9 +837,64 @@
}
\ior_close:N \g_@@_data_ior
\group_end:
-
% \end{macrocode}
%
+% \begin{macro}[EXP]{\__kernel_codepoint_case:nn}
+% \begin{macro}[EXP]{\@@_case:nnn}
+% \begin{macro}[EXP]
+% {\@@_uppercase:n, \@@_lowercase:n, \@@_titlecase:n, \@@_casefold:n}
+% \begin{macro}[EXP]{\@_case:nn}
+% With the core data files loaded, there is now a need to provide access to
+% this information for other modules. That is done here such that case
+% folding can also be covered. At this level, all that needs to be returned
+% is the
+% \begin{macrocode}
+\cs_new:Npn \__kernel_codepoint_case:nn #1#2
+ {
+ \exp_args:Ne \@@_case:nnn
+ { \codepoint_str_generate:n {#2} } {#1} {#2}
+ }
+\cs_new:Npn \@@_case:nnn #1#2#3
+ {
+ \cs_if_exist:cTF { c_@@_ #2 _ #1 _tl }
+ {
+ \tl_use:c
+ { c_@@_ #2 _ #1 _tl }
+ }
+ { \use:c { @@_ #2 :n } {#3} }
+ }
+\cs_new:Npn \@@_uppercase:n { \@@_case:nn { uppercase } }
+\cs_new:Npn \@@_lowercase:n { \@@_case:nn { lowercase } }
+\cs_new:Npn \@@_titlecase:n { \@@_case:nn { uppercase } }
+\cs_new:Npn \@@_casefold:n { \@@_case:nn { lowercase } }
+\cs_new:Npn \@@_case:nn #1#2
+ {
+ { \int_eval:n { \__kernel_codepoint_data:nn {#1} {#2} + #2 } }
+ { }
+ { }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_nfd:n}
+% \begin{macro}[EXP]{\@@_nfd:nn}
+% A simple interface.
+% \begin{macrocode}
+\cs_new:Npn \@@_nfd:n #1
+ { \exp_args:Ne \@@_nfd:nn { \codepoint_str_generate:n {#1} } {#1} }
+\cs_new:Npn \@@_nfd:nn #1#2
+ {
+ \tl_if_exist:cTF { c_@@_nfd_ #1 _tl }
+ { \tl_use:c { c_@@_nfd_ #1 _tl } }
+ { {#2} { } }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macrocode}
%<@@=text>
% \end{macrocode}
diff --git a/macros/latex/contrib/l3kernel/source3.pdf b/macros/latex/contrib/l3kernel/source3.pdf
index 14ca0f529d..1e3645636b 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 5a393bc8cd..55bfaf3a35 100644
--- a/macros/latex/contrib/l3kernel/source3.tex
+++ b/macros/latex/contrib/l3kernel/source3.tex
@@ -53,7 +53,7 @@ for those people who are interested.
{latex-team@latex-project.org}%
}%
}
-\date{Released 2022-11-02}
+\date{Released 2022-12-17}
\pagenumbering{roman}
\maketitle