[latex3-commits] [git/LaTeX3-latex3-latex3] master: Improve \char_<target>_case:N and add str version (95b7908)

Joseph Wright joseph.wright at morningstar2.co.uk
Fri May 3 19:49:24 CEST 2019


Repository : https://github.com/latex3/latex3
On branch  : master
Link       : https://github.com/latex3/latex3/commit/95b7908823c1a02459a174a383b59f558fe5914c

>---------------------------------------------------------------

commit 95b7908823c1a02459a174a383b59f558fe5914c
Author: Joseph Wright <joseph.wright at morningstar2.co.uk>
Date:   Fri May 3 18:47:02 2019 +0100

    Improve \char_<target>_case:N and add str version
    
    This came up after a discussion with Ulrike. The old behaviour was
    somewhat loose in terms of the catcode of the tokens produced. In this
    commit, that is addressed by ensuring that the output tokens are always
    re-generated to have the correct catcode. It also adds a str version,
    which will be quite a bit faster and which gives the correct behaviour
    in \str_<target>_case:n - that was not the case before.


>---------------------------------------------------------------

95b7908823c1a02459a174a383b59f558fe5914c
 l3kernel/CHANGELOG.md                   |    9 +
 l3kernel/l3candidates.dtx               |  109 +++++++++-
 l3kernel/l3str.dtx                      |    2 +-
 l3kernel/testfiles/m3char001.luatex.tlg |  168 ++++++++++++++++
 l3kernel/testfiles/m3char001.lvt        |   44 ++++
 l3kernel/testfiles/m3char001.tlg        |  332 +++++++++++++++++++++++++++++++
 l3kernel/testfiles/m3char001.xetex.tlg  |  168 ++++++++++++++++
 l3kernel/testfiles/m3expl001.luatex.tlg |   12 ++
 l3kernel/testfiles/m3expl001.ptex.tlg   |   12 ++
 l3kernel/testfiles/m3expl001.tlg        |   12 ++
 l3kernel/testfiles/m3expl001.uptex.tlg  |   12 ++
 l3kernel/testfiles/m3expl001.xetex.tlg  |   12 ++
 l3kernel/testfiles/m3expl003.luatex.tlg |   12 ++
 l3kernel/testfiles/m3expl003.ptex.tlg   |   12 ++
 l3kernel/testfiles/m3expl003.tlg        |   12 ++
 l3kernel/testfiles/m3expl003.uptex.tlg  |   12 ++
 l3kernel/testfiles/m3expl003.xetex.tlg  |   12 ++
 17 files changed, 945 insertions(+), 7 deletions(-)

diff --git a/l3kernel/CHANGELOG.md b/l3kernel/CHANGELOG.md
index 06c0eee..d267b56 100644
--- a/l3kernel/CHANGELOG.md
+++ b/l3kernel/CHANGELOG.md
@@ -7,6 +7,15 @@ this project uses date-based 'snapshot' version identifiers.
 
 ## [Unreleased]
 
+### Added
+
+- `\char_str_<target>_case:N`
+
+### Fixed
+
+- Category code of output from `\char_<target>_case:N`, and
+  same issue in `\str_<target>_case:n`
+
 ## [2019-05-03]
 
 ### Added
diff --git a/l3kernel/l3candidates.dtx b/l3kernel/l3candidates.dtx
index 39a6dd5..459e708 100644
--- a/l3kernel/l3candidates.dtx
+++ b/l3kernel/l3candidates.dtx
@@ -1220,10 +1220,12 @@
 %   (\enquote{active}), and character code $32$ (space).
 % \end{variable}
 %
-% \begin{function}[added = 2018-04-06, EXP]
+% \begin{function}[added = 2018-04-06, updated = 201-05-03, EXP]
 %   {
 %     \char_lower_case:N, \char_upper_case:N,
-%     \char_mixed_case:N, \char_fold_case:N
+%     \char_mixed_case:N, \char_fold_case:N,
+%     \char_str_lower_case:N, \char_str_upper_case:N,
+%     \char_str_mixed_case:N, \char_str_fold_case:N,
 %   }
 %   \begin{syntax}
 %     \cs{char_lower_case:N} \meta{char}
@@ -1232,7 +1234,10 @@
 %   as detailed by the function name (see \cs{str_fold_case:n}
 %   and \cs{tl_mixed_case:n} for details of these terms). The case mapping
 %   is carried out with no context-dependence (\emph{cf.}~\cs{tl_upper_case:n},
-%   \emph{etc.})
+%   \emph{etc.}) The \texttt{str} versions always generate \enquote{other}
+%   (category code $12$) characters, whilst the standard versions generate
+%   characters with the currently-active category code (\emph{i.e.}~as if
+%   the character had been read directly here).
 % \end{function}
 %
 % \begin{function}[added = 2018-06-01, EXP]{\char_codepoint_to_bytes:n}
@@ -2343,6 +2348,18 @@
 %   }
 % \begin{macro}{\@@_change_case:nNN}
 % \begin{macro}{\@@_change_case:nN}
+% \begin{macro}{\@@_change_case_multi:n, \@@_change_case_multi:v}
+% \begin{macro}{\@@_change_case_multi:NNNw}
+% \begin{macro}{\@@_change_case:NN}
+% \begin{macro}{\@@_change_case:NNN}
+% \begin{macro}{\@@_change_case:N}
+% \begin{macro}
+%   {
+%     \char_str_lower_case:N, \char_str_upper_case:N,
+%     \char_str_mixed_case:N, \char_str_fold_case:N
+%   }
+% \begin{macro}{\@@_str_change_case:nNN}
+% \begin{macro}{\@@_str_change_case:nN}
 %   Expandable character generation is done using a two-part approach.
 %   First, see if the current character has a special mapping for the current
 %   transformation. If it does, insert that. Otherwise, use the \TeX{} data
@@ -2351,6 +2368,12 @@
 %   may be special-cased or might be a special upper case outcome. The internal
 %   when using non-Unicode engines has to be set up to only do anything
 %   with ASCII characters.
+%
+%  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 maintiain
+%  \texttt{f}-type expandability.
 %    \begin{macrocode}
 \cs_new:Npn \char_lower_case:N #1
   { \@@_change_case:nNN { lower } \char_value_lccode:n #1 }
@@ -2359,7 +2382,10 @@
 \cs_new:Npn \char_mixed_case:N #1
   {
     \tl_if_exist:cTF { c_@@_mixed_case_ \token_to_str:N #1 _tl }
-      { \tl_use:c { c_@@_mixed_case_ \token_to_str:N #1 _tl } }
+      {
+        \@@_change_case_multi:v
+          { c_@@_mixed_case_ \token_to_str:N #1 _tl }
+      }
       { \char_upper_case:N #1 }
   }
 \cs_new:Npn \char_fold_case:N #1
@@ -2367,20 +2393,91 @@
 \cs_new:Npn \@@_change_case:nNN #1#2#3
   {
     \tl_if_exist:cTF { c_@@_ #1 _case_ \token_to_str:N #3 _tl }
-      { \tl_use:c { c_@@_ #1 _case_ \token_to_str:N #3 _tl } }
+      {
+        \@@_change_case_multi:v
+          { c_@@_ #1 _case_ \token_to_str:N #3 _tl }
+      }
       { \exp_args:Nf \@@_change_case:nN { #2 { `#3 } } #3 }
   }
 \cs_new:Npn \@@_change_case:nN #1#2
   {
     \int_compare:nNnTF {#1} = 0
-      {#2}
+      { \@@_change_case:N #2 }
       { \char_generate:nn {#1} { \char_value_catcode:n {#1} } }
   }
+\cs_new:Npn \@@_change_case_multi:n #1
+  { \@@_change_case_multi:NNNw #1 \q_no_value \q_no_value \q_stop }
+\cs_new:Npn \@@_change_case_multi:NNNw #1#2#3#4 \q_stop
+  {
+    \quark_if_no_value:NTF #3
+      {
+        \quark_if_no_value:NTF #2
+          { \@@_change_case:N #1 }
+          { \@@_change_case:NN #1#2 }
+      }
+      { \@@_change_case:NNN #1#2#3 }
+  }
+\cs_generate_variant:Nn \@@_change_case_multi:n { v }
+\cs_new:Npn \@@_change_case:NN #1#2
+  {
+    \exp_args:Nnf \use:nn
+      { \@@_change_case:N #1 }
+      { \@@_change_case:N #2 }
+  }
+\cs_new:Npn \@@_change_case:NNN #1#2#3
+  {
+    \exp_args:Nnff \use:nnn
+      { \@@_change_case:N #1 }
+      { \@@_change_case:N #2 }
+      { \@@_change_case:N #3 }
+  }
+\cs_new:Npn \@@_change_case:N #1
+  { \char_generate:nn { `#1 } { \char_value_catcode:n { `#1 } } }
 \bool_lazy_or:nnF { \sys_if_engine_luatex_p: } { \sys_if_engine_xetex_p: }
   {
     \cs_set_eq:NN \@@_change_case:nN \use_ii:nn
   }
 %    \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_lower_case:N #1
+  { \@@_str_change_case:nNN { lower } \char_value_lccode:n #1 }
+\cs_new:Npn \char_str_upper_case:N #1
+  { \@@_str_change_case:nNN { upper } \char_value_uccode:n #1 }
+\cs_new:Npn \char_str_mixed_case:N #1
+  {
+    \tl_if_exist:cTF { c_@@_mixed_case_ \token_to_str:N #1 _tl }
+      { \tl_to_str:c { c_@@_mixed_case_ \token_to_str:N #1 _tl } }
+      { \char_str_upper_case:N #1 }
+  }
+\cs_new:Npn \char_str_fold_case: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 }
+  }
+\cs_new:Npn \@@_str_change_case:nN #1#2
+  {
+    \int_compare:nNnTF {#1} = 0
+      { \tl_to_str:n {#2} }
+      { \char_generate:nn {#1} { 12 } }
+  }
+\bool_lazy_or:nnF { \sys_if_engine_luatex_p: } { \sys_if_engine_xetex_p: }
+  {
+    \cs_set_eq:NN \@@_str_change_case:nN \use_ii:nn
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
 % \end{macro}
 % \end{macro}
 % \end{macro}
diff --git a/l3kernel/l3str.dtx b/l3kernel/l3str.dtx
index 7c3e2c7..0021906 100644
--- a/l3kernel/l3str.dtx
+++ b/l3kernel/l3str.dtx
@@ -1890,7 +1890,7 @@
     \quark_if_recursion_tail_stop_do:Nn #2
       { \@@_change_case_end:wn }
     \@@_change_case_output:fw
-      { \use:c { char_ #1 _case:N } #2 }
+      { \use:c { char_str_ #1 _case:N } #2 }
     \@@_change_case_loop:nw {#1}
   }
 %    \end{macrocode}
diff --git a/l3kernel/testfiles/m3char001.luatex.tlg b/l3kernel/testfiles/m3char001.luatex.tlg
index 1e4c5de..54bf03e 100644
--- a/l3kernel/testfiles/m3char001.luatex.tlg
+++ b/l3kernel/testfiles/m3char001.luatex.tlg
@@ -499,3 +499,171 @@ the letter A
 the character A
 undefined
 ============================================================
+============================================================
+TEST 9: \char_ <thing>_case:N
+============================================================
+The token list contains the tokens:
+>  a (the letter a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the letter A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  a (the letter a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the letter A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the letter z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the letter Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the letter z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the letter Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  dž (the letter dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  DŽ (the letter DŽ).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  dž (the letter dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Dž (the letter Dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  q (the letter q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  q (the letter q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+============================================================
+============================================================
+TEST 10: \char_str_ <thing>_case:N
+============================================================
+The token list contains the tokens:
+>  a (the character a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the character A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  a (the character a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the character A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the character z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the character Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the character z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the character Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  dž (the character dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  DŽ (the character DŽ).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  dž (the character dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Dž (the character Dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  q (the character q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  q (the character q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+============================================================
diff --git a/l3kernel/testfiles/m3char001.lvt b/l3kernel/testfiles/m3char001.lvt
index 5d36e5f..08b641f 100644
--- a/l3kernel/testfiles/m3char001.lvt
+++ b/l3kernel/testfiles/m3char001.lvt
@@ -169,4 +169,48 @@
     \test:nn { 65 } { 13 }
   }
 
+\OMIT
+\cs_gset_protected:Npn \test:N #1
+  {
+    \exp_args:Nf \tl_analysis_show:n { \char_lower_case:N #1 }
+    \exp_args:Nf \tl_analysis_show:n { \char_upper_case:N #1 }
+    \exp_args:Nf \tl_analysis_show:n { \char_fold_case:N #1 }
+    \exp_args:Nf \tl_analysis_show:n { \char_mixed_case:N #1 }
+  }
+\TIMO
+
+\group_begin:
+  \char_set_catcode_other:N Q
+  \TEST { \char_<thing>_case:N }
+    {
+      \test:N A
+      \test:N Z
+      \test:N *
+      \test:N DŽ
+      \test:N q
+    }
+\group_end:
+
+\OMIT
+\cs_gset_protected:Npn \test:N #1
+  {
+    \exp_args:Nf \tl_analysis_show:n { \char_str_lower_case:N #1 }
+    \exp_args:Nf \tl_analysis_show:n { \char_str_upper_case:N #1 }
+    \exp_args:Nf \tl_analysis_show:n { \char_str_fold_case:N #1 }
+    \exp_args:Nf \tl_analysis_show:n { \char_str_mixed_case:N #1 }
+  }
+\TIMO
+
+\group_begin:
+  \char_set_catcode_other:N Q
+  \TEST { \char_str_<thing>_case:N }
+    {
+      \test:N A
+      \test:N Z
+      \test:N *
+      \test:N DŽ
+      \test:N q
+    }
+\group_end:
+
 \END
diff --git a/l3kernel/testfiles/m3char001.tlg b/l3kernel/testfiles/m3char001.tlg
index 4887919..ff98283 100644
--- a/l3kernel/testfiles/m3char001.tlg
+++ b/l3kernel/testfiles/m3char001.tlg
@@ -534,3 +534,335 @@ the letter A
 the character A
 undefined
 ============================================================
+============================================================
+TEST 9: \char_ <thing>_case:N
+============================================================
+The token list contains the tokens:
+>  a (the letter a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the letter A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  a (the letter a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the letter A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the letter z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the letter Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the letter z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the letter Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+! Argument of \UTFviii at two@octets has an extra }.
+<inserted text> 
+                \par 
+l. ...    }
+I've run across a `}' that doesn't seem to match anything.
+For example, `\def\a#1{...}' and `\a}' would produce
+this error. If you simply proceed now, the `\par' that
+I've just inserted will cause me to report a runaway
+argument that might be the root of the problem. But if
+your `}' was spurious, just type `2' and it will go away.
+Runaway argument?
+! Paragraph ended before \UTFviii at two@octets was complete.
+<to be read again> 
+                   \par 
+l. ...    }
+I suspect you've forgotten a `}', causing me to apply this
+control sequence to too much text. How can we recover?
+My plan is to forget the whole thing and hope for the best.
+The token list contains the tokens:
+>  \par (control sequence=\par).
+<recently read> }
+l. ...    }
+! Argument of \UTFviii at two@octets has an extra }.
+<inserted text> 
+                \par 
+l. ...    }
+I've run across a `}' that doesn't seem to match anything.
+For example, `\def\a#1{...}' and `\a}' would produce
+this error. If you simply proceed now, the `\par' that
+I've just inserted will cause me to report a runaway
+argument that might be the root of the problem. But if
+your `}' was spurious, just type `2' and it will go away.
+Runaway argument?
+! Paragraph ended before \UTFviii at two@octets was complete.
+<to be read again> 
+                   \par 
+l. ...    }
+I suspect you've forgotten a `}', causing me to apply this
+control sequence to too much text. How can we recover?
+My plan is to forget the whole thing and hope for the best.
+The token list contains the tokens:
+>  \par (control sequence=\par).
+<recently read> }
+l. ...    }
+! Argument of \UTFviii at two@octets has an extra }.
+<inserted text> 
+                \par 
+l. ...    }
+I've run across a `}' that doesn't seem to match anything.
+For example, `\def\a#1{...}' and `\a}' would produce
+this error. If you simply proceed now, the `\par' that
+I've just inserted will cause me to report a runaway
+argument that might be the root of the problem. But if
+your `}' was spurious, just type `2' and it will go away.
+Runaway argument?
+! Paragraph ended before \UTFviii at two@octets was complete.
+<to be read again> 
+                   \par 
+l. ...    }
+I suspect you've forgotten a `}', causing me to apply this
+control sequence to too much text. How can we recover?
+My plan is to forget the whole thing and hope for the best.
+The token list contains the tokens:
+>  \par (control sequence=\par).
+<recently read> }
+l. ...    }
+! Argument of \UTFviii at two@octets has an extra }.
+<inserted text> 
+                \par 
+l. ...    }
+I've run across a `}' that doesn't seem to match anything.
+For example, `\def\a#1{...}' and `\a}' would produce
+this error. If you simply proceed now, the `\par' that
+I've just inserted will cause me to report a runaway
+argument that might be the root of the problem. But if
+your `}' was spurious, just type `2' and it will go away.
+Runaway argument?
+! Paragraph ended before \UTFviii at two@octets was complete.
+<to be read again> 
+                   \par 
+l. ...    }
+I suspect you've forgotten a `}', causing me to apply this
+control sequence to too much text. How can we recover?
+My plan is to forget the whole thing and hope for the best.
+The token list contains the tokens:
+>  \par (control sequence=\par).
+<recently read> }
+l. ...    }
+! Package inputenc Error: Invalid UTF-8 byte "84.
+See the inputenc package documentation for explanation.
+Type  H <return>  for immediate help.
+ ...                                              
+l. ...    }
+The document does not appear to be in UTF-8 encoding.
+Try adding \UseRawInputEncoding as the first line of the file
+or specify an encoding such as \usepackage [latin1]{inputenc}
+in the document preamble.
+Alternatively, save the file in UTF-8 using your editor or another tool
+The token list contains the tokens:
+>  q (the letter q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  q (the letter q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+============================================================
+============================================================
+TEST 10: \char_str_ <thing>_case:N
+============================================================
+The token list contains the tokens:
+>  a (the character a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the letter A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  a (the character a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the letter A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the character z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the letter Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the character z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the letter Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+! Argument of \UTFviii at two@octets has an extra }.
+<inserted text> 
+                \par 
+l. ...    }
+I've run across a `}' that doesn't seem to match anything.
+For example, `\def\a#1{...}' and `\a}' would produce
+this error. If you simply proceed now, the `\par' that
+I've just inserted will cause me to report a runaway
+argument that might be the root of the problem. But if
+your `}' was spurious, just type `2' and it will go away.
+Runaway argument?
+! Paragraph ended before \UTFviii at two@octets was complete.
+<to be read again> 
+                   \par 
+l. ...    }
+I suspect you've forgotten a `}', causing me to apply this
+control sequence to too much text. How can we recover?
+My plan is to forget the whole thing and hope for the best.
+The token list contains the tokens:
+>  \par (control sequence=\par).
+<recently read> }
+l. ...    }
+! Argument of \UTFviii at two@octets has an extra }.
+<inserted text> 
+                \par 
+l. ...    }
+I've run across a `}' that doesn't seem to match anything.
+For example, `\def\a#1{...}' and `\a}' would produce
+this error. If you simply proceed now, the `\par' that
+I've just inserted will cause me to report a runaway
+argument that might be the root of the problem. But if
+your `}' was spurious, just type `2' and it will go away.
+Runaway argument?
+! Paragraph ended before \UTFviii at two@octets was complete.
+<to be read again> 
+                   \par 
+l. ...    }
+I suspect you've forgotten a `}', causing me to apply this
+control sequence to too much text. How can we recover?
+My plan is to forget the whole thing and hope for the best.
+The token list contains the tokens:
+>  \par (control sequence=\par).
+<recently read> }
+l. ...    }
+! Argument of \UTFviii at two@octets has an extra }.
+<inserted text> 
+                \par 
+l. ...    }
+I've run across a `}' that doesn't seem to match anything.
+For example, `\def\a#1{...}' and `\a}' would produce
+this error. If you simply proceed now, the `\par' that
+I've just inserted will cause me to report a runaway
+argument that might be the root of the problem. But if
+your `}' was spurious, just type `2' and it will go away.
+Runaway argument?
+! Paragraph ended before \UTFviii at two@octets was complete.
+<to be read again> 
+                   \par 
+l. ...    }
+I suspect you've forgotten a `}', causing me to apply this
+control sequence to too much text. How can we recover?
+My plan is to forget the whole thing and hope for the best.
+The token list contains the tokens:
+>  \par (control sequence=\par).
+<recently read> }
+l. ...    }
+! Argument of \UTFviii at two@octets has an extra }.
+<inserted text> 
+                \par 
+l. ...    }
+I've run across a `}' that doesn't seem to match anything.
+For example, `\def\a#1{...}' and `\a}' would produce
+this error. If you simply proceed now, the `\par' that
+I've just inserted will cause me to report a runaway
+argument that might be the root of the problem. But if
+your `}' was spurious, just type `2' and it will go away.
+Runaway argument?
+! Paragraph ended before \UTFviii at two@octets was complete.
+<to be read again> 
+                   \par 
+l. ...    }
+I suspect you've forgotten a `}', causing me to apply this
+control sequence to too much text. How can we recover?
+My plan is to forget the whole thing and hope for the best.
+The token list contains the tokens:
+>  \par (control sequence=\par).
+<recently read> }
+l. ...    }
+! Package inputenc Error: Invalid UTF-8 byte "84.
+See the inputenc package documentation for explanation.
+Type  H <return>  for immediate help.
+ ...                                              
+l. ...    }
+The document does not appear to be in UTF-8 encoding.
+Try adding \UseRawInputEncoding as the first line of the file
+or specify an encoding such as \usepackage [latin1]{inputenc}
+in the document preamble.
+Alternatively, save the file in UTF-8 using your editor or another tool
+The token list contains the tokens:
+>  q (the letter q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  q (the letter q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+============================================================
diff --git a/l3kernel/testfiles/m3char001.xetex.tlg b/l3kernel/testfiles/m3char001.xetex.tlg
index 1d0fb3c..f1b4319 100644
--- a/l3kernel/testfiles/m3char001.xetex.tlg
+++ b/l3kernel/testfiles/m3char001.xetex.tlg
@@ -499,3 +499,171 @@ the letter A
 the character A
 undefined
 ============================================================
+============================================================
+TEST 9: \char_ <thing>_case:N
+============================================================
+The token list contains the tokens:
+>  a (the letter a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the letter A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  a (the letter a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the letter A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the letter z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the letter Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the letter z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the letter Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  dž (the letter dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  DŽ (the letter DŽ).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  dž (the letter dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Dž (the letter Dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  q (the letter q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  q (the letter q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+============================================================
+============================================================
+TEST 10: \char_str_ <thing>_case:N
+============================================================
+The token list contains the tokens:
+>  a (the character a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the character A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  a (the character a).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  A (the character A).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the character z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the character Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  z (the character z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Z (the character Z).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  * (the character *).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  dž (the character dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  DŽ (the character DŽ).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  dž (the character dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Dž (the character Dž).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  q (the character q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  q (the character q).
+<recently read> }
+l. ...    }
+The token list contains the tokens:
+>  Q (the character Q).
+<recently read> }
+l. ...    }
+============================================================
diff --git a/l3kernel/testfiles/m3expl001.luatex.tlg b/l3kernel/testfiles/m3expl001.luatex.tlg
index fe7be97..0ccf76e 100644
--- a/l3kernel/testfiles/m3expl001.luatex.tlg
+++ b/l3kernel/testfiles/m3expl001.luatex.tlg
@@ -6051,6 +6051,18 @@ Defining \char_mixed_case:N on line ...
 Defining \char_fold_case:N on line ...
 Defining \__char_change_case:nNN on line ...
 Defining \__char_change_case:nN on line ...
+Defining \__char_change_case_multi:n on line ...
+Defining \__char_change_case_multi:NNNw on line ...
+Defining \__char_change_case_multi:v on line ...
+Defining \__char_change_case:NN on line ...
+Defining \__char_change_case:NNN on line ...
+Defining \__char_change_case:N on line ...
+Defining \char_str_lower_case:N on line ...
+Defining \char_str_upper_case:N on line ...
+Defining \char_str_mixed_case:N on line ...
+Defining \char_str_fold_case:N on line ...
+Defining \__char_str_change_case:nNN on line ...
+Defining \__char_str_change_case:nN on line ...
 Defining \char_codepoint_to_bytes:n on line ...
 Defining \__char_codepoint_to_bytes_auxi:n on line ...
 Defining \__char_codepoint_to_bytes_auxii:Nnn on line ...
diff --git a/l3kernel/testfiles/m3expl001.ptex.tlg b/l3kernel/testfiles/m3expl001.ptex.tlg
index 4d4e3ff..1a30122 100644
--- a/l3kernel/testfiles/m3expl001.ptex.tlg
+++ b/l3kernel/testfiles/m3expl001.ptex.tlg
@@ -6046,6 +6046,18 @@ Defining \char_mixed_case:N on line ...
 Defining \char_fold_case:N on line ...
 Defining \__char_change_case:nNN on line ...
 Defining \__char_change_case:nN on line ...
+Defining \__char_change_case_multi:n on line ...
+Defining \__char_change_case_multi:NNNw on line ...
+Defining \__char_change_case_multi:v on line ...
+Defining \__char_change_case:NN on line ...
+Defining \__char_change_case:NNN on line ...
+Defining \__char_change_case:N on line ...
+Defining \char_str_lower_case:N on line ...
+Defining \char_str_upper_case:N on line ...
+Defining \char_str_mixed_case:N on line ...
+Defining \char_str_fold_case:N on line ...
+Defining \__char_str_change_case:nNN on line ...
+Defining \__char_str_change_case:nN on line ...
 Defining \char_codepoint_to_bytes:n on line ...
 Defining \__char_codepoint_to_bytes_auxi:n on line ...
 Defining \__char_codepoint_to_bytes_auxii:Nnn on line ...
diff --git a/l3kernel/testfiles/m3expl001.tlg b/l3kernel/testfiles/m3expl001.tlg
index ee37c44..ae40105 100644
--- a/l3kernel/testfiles/m3expl001.tlg
+++ b/l3kernel/testfiles/m3expl001.tlg
@@ -6046,6 +6046,18 @@ Defining \char_mixed_case:N on line ...
 Defining \char_fold_case:N on line ...
 Defining \__char_change_case:nNN on line ...
 Defining \__char_change_case:nN on line ...
+Defining \__char_change_case_multi:n on line ...
+Defining \__char_change_case_multi:NNNw on line ...
+Defining \__char_change_case_multi:v on line ...
+Defining \__char_change_case:NN on line ...
+Defining \__char_change_case:NNN on line ...
+Defining \__char_change_case:N on line ...
+Defining \char_str_lower_case:N on line ...
+Defining \char_str_upper_case:N on line ...
+Defining \char_str_mixed_case:N on line ...
+Defining \char_str_fold_case:N on line ...
+Defining \__char_str_change_case:nNN on line ...
+Defining \__char_str_change_case:nN on line ...
 Defining \char_codepoint_to_bytes:n on line ...
 Defining \__char_codepoint_to_bytes_auxi:n on line ...
 Defining \__char_codepoint_to_bytes_auxii:Nnn on line ...
diff --git a/l3kernel/testfiles/m3expl001.uptex.tlg b/l3kernel/testfiles/m3expl001.uptex.tlg
index d265d55..1bd8e77 100644
--- a/l3kernel/testfiles/m3expl001.uptex.tlg
+++ b/l3kernel/testfiles/m3expl001.uptex.tlg
@@ -6043,6 +6043,18 @@ Defining \char_mixed_case:N on line ...
 Defining \char_fold_case:N on line ...
 Defining \__char_change_case:nNN on line ...
 Defining \__char_change_case:nN on line ...
+Defining \__char_change_case_multi:n on line ...
+Defining \__char_change_case_multi:NNNw on line ...
+Defining \__char_change_case_multi:v on line ...
+Defining \__char_change_case:NN on line ...
+Defining \__char_change_case:NNN on line ...
+Defining \__char_change_case:N on line ...
+Defining \char_str_lower_case:N on line ...
+Defining \char_str_upper_case:N on line ...
+Defining \char_str_mixed_case:N on line ...
+Defining \char_str_fold_case:N on line ...
+Defining \__char_str_change_case:nNN on line ...
+Defining \__char_str_change_case:nN on line ...
 Defining \char_codepoint_to_bytes:n on line ...
 Defining \__char_codepoint_to_bytes_auxi:n on line ...
 Defining \__char_codepoint_to_bytes_auxii:Nnn on line ...
diff --git a/l3kernel/testfiles/m3expl001.xetex.tlg b/l3kernel/testfiles/m3expl001.xetex.tlg
index c0549a7..75abd72 100644
--- a/l3kernel/testfiles/m3expl001.xetex.tlg
+++ b/l3kernel/testfiles/m3expl001.xetex.tlg
@@ -6050,6 +6050,18 @@ Defining \char_mixed_case:N on line ...
 Defining \char_fold_case:N on line ...
 Defining \__char_change_case:nNN on line ...
 Defining \__char_change_case:nN on line ...
+Defining \__char_change_case_multi:n on line ...
+Defining \__char_change_case_multi:NNNw on line ...
+Defining \__char_change_case_multi:v on line ...
+Defining \__char_change_case:NN on line ...
+Defining \__char_change_case:NNN on line ...
+Defining \__char_change_case:N on line ...
+Defining \char_str_lower_case:N on line ...
+Defining \char_str_upper_case:N on line ...
+Defining \char_str_mixed_case:N on line ...
+Defining \char_str_fold_case:N on line ...
+Defining \__char_str_change_case:nNN on line ...
+Defining \__char_str_change_case:nN on line ...
 Defining \char_codepoint_to_bytes:n on line ...
 Defining \__char_codepoint_to_bytes_auxi:n on line ...
 Defining \__char_codepoint_to_bytes_auxii:Nnn on line ...
diff --git a/l3kernel/testfiles/m3expl003.luatex.tlg b/l3kernel/testfiles/m3expl003.luatex.tlg
index fe7be97..0ccf76e 100644
--- a/l3kernel/testfiles/m3expl003.luatex.tlg
+++ b/l3kernel/testfiles/m3expl003.luatex.tlg
@@ -6051,6 +6051,18 @@ Defining \char_mixed_case:N on line ...
 Defining \char_fold_case:N on line ...
 Defining \__char_change_case:nNN on line ...
 Defining \__char_change_case:nN on line ...
+Defining \__char_change_case_multi:n on line ...
+Defining \__char_change_case_multi:NNNw on line ...
+Defining \__char_change_case_multi:v on line ...
+Defining \__char_change_case:NN on line ...
+Defining \__char_change_case:NNN on line ...
+Defining \__char_change_case:N on line ...
+Defining \char_str_lower_case:N on line ...
+Defining \char_str_upper_case:N on line ...
+Defining \char_str_mixed_case:N on line ...
+Defining \char_str_fold_case:N on line ...
+Defining \__char_str_change_case:nNN on line ...
+Defining \__char_str_change_case:nN on line ...
 Defining \char_codepoint_to_bytes:n on line ...
 Defining \__char_codepoint_to_bytes_auxi:n on line ...
 Defining \__char_codepoint_to_bytes_auxii:Nnn on line ...
diff --git a/l3kernel/testfiles/m3expl003.ptex.tlg b/l3kernel/testfiles/m3expl003.ptex.tlg
index 4d4e3ff..1a30122 100644
--- a/l3kernel/testfiles/m3expl003.ptex.tlg
+++ b/l3kernel/testfiles/m3expl003.ptex.tlg
@@ -6046,6 +6046,18 @@ Defining \char_mixed_case:N on line ...
 Defining \char_fold_case:N on line ...
 Defining \__char_change_case:nNN on line ...
 Defining \__char_change_case:nN on line ...
+Defining \__char_change_case_multi:n on line ...
+Defining \__char_change_case_multi:NNNw on line ...
+Defining \__char_change_case_multi:v on line ...
+Defining \__char_change_case:NN on line ...
+Defining \__char_change_case:NNN on line ...
+Defining \__char_change_case:N on line ...
+Defining \char_str_lower_case:N on line ...
+Defining \char_str_upper_case:N on line ...
+Defining \char_str_mixed_case:N on line ...
+Defining \char_str_fold_case:N on line ...
+Defining \__char_str_change_case:nNN on line ...
+Defining \__char_str_change_case:nN on line ...
 Defining \char_codepoint_to_bytes:n on line ...
 Defining \__char_codepoint_to_bytes_auxi:n on line ...
 Defining \__char_codepoint_to_bytes_auxii:Nnn on line ...
diff --git a/l3kernel/testfiles/m3expl003.tlg b/l3kernel/testfiles/m3expl003.tlg
index ee37c44..ae40105 100644
--- a/l3kernel/testfiles/m3expl003.tlg
+++ b/l3kernel/testfiles/m3expl003.tlg
@@ -6046,6 +6046,18 @@ Defining \char_mixed_case:N on line ...
 Defining \char_fold_case:N on line ...
 Defining \__char_change_case:nNN on line ...
 Defining \__char_change_case:nN on line ...
+Defining \__char_change_case_multi:n on line ...
+Defining \__char_change_case_multi:NNNw on line ...
+Defining \__char_change_case_multi:v on line ...
+Defining \__char_change_case:NN on line ...
+Defining \__char_change_case:NNN on line ...
+Defining \__char_change_case:N on line ...
+Defining \char_str_lower_case:N on line ...
+Defining \char_str_upper_case:N on line ...
+Defining \char_str_mixed_case:N on line ...
+Defining \char_str_fold_case:N on line ...
+Defining \__char_str_change_case:nNN on line ...
+Defining \__char_str_change_case:nN on line ...
 Defining \char_codepoint_to_bytes:n on line ...
 Defining \__char_codepoint_to_bytes_auxi:n on line ...
 Defining \__char_codepoint_to_bytes_auxii:Nnn on line ...
diff --git a/l3kernel/testfiles/m3expl003.uptex.tlg b/l3kernel/testfiles/m3expl003.uptex.tlg
index d265d55..1bd8e77 100644
--- a/l3kernel/testfiles/m3expl003.uptex.tlg
+++ b/l3kernel/testfiles/m3expl003.uptex.tlg
@@ -6043,6 +6043,18 @@ Defining \char_mixed_case:N on line ...
 Defining \char_fold_case:N on line ...
 Defining \__char_change_case:nNN on line ...
 Defining \__char_change_case:nN on line ...
+Defining \__char_change_case_multi:n on line ...
+Defining \__char_change_case_multi:NNNw on line ...
+Defining \__char_change_case_multi:v on line ...
+Defining \__char_change_case:NN on line ...
+Defining \__char_change_case:NNN on line ...
+Defining \__char_change_case:N on line ...
+Defining \char_str_lower_case:N on line ...
+Defining \char_str_upper_case:N on line ...
+Defining \char_str_mixed_case:N on line ...
+Defining \char_str_fold_case:N on line ...
+Defining \__char_str_change_case:nNN on line ...
+Defining \__char_str_change_case:nN on line ...
 Defining \char_codepoint_to_bytes:n on line ...
 Defining \__char_codepoint_to_bytes_auxi:n on line ...
 Defining \__char_codepoint_to_bytes_auxii:Nnn on line ...
diff --git a/l3kernel/testfiles/m3expl003.xetex.tlg b/l3kernel/testfiles/m3expl003.xetex.tlg
index c0549a7..75abd72 100644
--- a/l3kernel/testfiles/m3expl003.xetex.tlg
+++ b/l3kernel/testfiles/m3expl003.xetex.tlg
@@ -6050,6 +6050,18 @@ Defining \char_mixed_case:N on line ...
 Defining \char_fold_case:N on line ...
 Defining \__char_change_case:nNN on line ...
 Defining \__char_change_case:nN on line ...
+Defining \__char_change_case_multi:n on line ...
+Defining \__char_change_case_multi:NNNw on line ...
+Defining \__char_change_case_multi:v on line ...
+Defining \__char_change_case:NN on line ...
+Defining \__char_change_case:NNN on line ...
+Defining \__char_change_case:N on line ...
+Defining \char_str_lower_case:N on line ...
+Defining \char_str_upper_case:N on line ...
+Defining \char_str_mixed_case:N on line ...
+Defining \char_str_fold_case:N on line ...
+Defining \__char_str_change_case:nNN on line ...
+Defining \__char_str_change_case:nN on line ...
 Defining \char_codepoint_to_bytes:n on line ...
 Defining \__char_codepoint_to_bytes_auxi:n on line ...
 Defining \__char_codepoint_to_bytes_auxii:Nnn on line ...





More information about the latex3-commits mailing list