diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx | 978 |
1 files changed, 507 insertions, 471 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx index 9a19df41122..8bceb8e6661 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -%% File: l3candidates.dtx Copyright(C) 2012-2015 The LaTeX3 Project +%% File: l3candidates.dtx Copyright(C) 2012-2016 The LaTeX3 Project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -38,7 +38,7 @@ \documentclass[full]{l3doc} %</driver> %<*driver|package> -\GetIdInfo$Id: l3candidates.dtx 6325 2015-12-20 18:07:35Z joseph $ +\GetIdInfo$Id: l3candidates.dtx 6376 2016-01-14 08:36:20Z joseph $ {L3 Experimental additions to l3kernel} %</driver|package> %<*driver> @@ -860,7 +860,7 @@ % giving an \meta{integer denotation}. % \end{function} % -% \begin{function}[EXP, added = 2014-06-30, updated = 2015-05-07]^^A +% \begin{function}[EXP, added = 2014-06-30, updated = 2016-01-12]^^A % { % \tl_lower_case:n, \tl_upper_case:n, \tl_mixed_case:n, % \tl_lower_case:nn, \tl_upper_case:nn, \tl_mixed_case:nn @@ -958,12 +958,21 @@ % case changing. % \end{variable} % -% In package mode, the case change system will also -% convert text stored using the \LaTeXe{} \enquote{LICR} approach. This -% will upper/lower case tokens as implemented for the font encodings -% \texttt{T1}, \texttt{T2}, \texttt{T5} and \texttt{LGR} (see the behaviour of -% the \LaTeXe{} command \tn{MakeUppercase}). Note that these commands will -% automatically be protected from expansion. +% \begin{variable}{\l_tl_case_change_accents_tl} +% This list specifies accent commands which should be left unexpanded +% in the output. This allows for example +% \begin{verbatim} +% \tl_upper_case:n { \" { a } } +% \end{verbatim} +% to yield +% \begin{verbatim} +% \" { A } +% \end{verbatim} +% irrespective of the expandability of |\"|. +% +% The standard contents of this variable is |\"|, |\^|, |\'|, +% |\`|, |\.|, |\c|, |\u|, |\~|, |\H| and |\v| +% \end{variable} % % \enquote{Mixed} case conversion may be regarded informally as converting the % first character of the \meta{tokens} to upper case and the rest to lower @@ -998,16 +1007,16 @@ % \end{variable} % % As is generally true for \pkg{expl3}, these functions are designed to -% work with Unicode input only. As such, when used with \pdfTeX{} -% \emph{only} the characters \texttt{a}--\texttt{zA}--\texttt{Z} are -% modified. When used with \XeTeX{} or \LuaTeX{} a full range of Unicode -% transformations are enabled. Specifically, the standard mappings here -% follow those defined by the \href{http://www.unicode.org}^^A +% 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 +% here follow those defined by the \href{http://www.unicode.org}^^A % {Unicode Consortium} in \texttt{UnicodeData.txt} and -% \texttt{SpecialCasing.txt}. Note that in some cases, \pdfTeX{} can -% interpret the input to a case change but not generate the correct output -% (for example in the mapping i to I-dot in Turkish): in these cases the -% input is left unchanged. +% \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| font encoding. Thus for example |รค| can be case-changed +% using \pdfTeX{}. For \pTeX{} only the ASCII range is covered as the +% engine treats input outside of this range as east Asian. % % Context-sensitive mappings are enabled: language-dependent cases are % discussed below. Context detection will expand input but treats any @@ -3065,6 +3074,7 @@ % \@@_change_case_output:nwn , % \@@_change_case_output:Vwn , % \@@_change_case_output:own , +% \@@_change_case_output:Vwn , % \@@_change_case_output:fwn , % } % \begin{macro}[aux, EXP]{\@@_change_case_end:wn} @@ -3080,16 +3090,16 @@ % \begin{macro}[aux, EXP]{\@@_change_case_N_type:Nnnn} % \begin{macro}[aux, EXP]{\@@_change_case_char:Nnn} % \begin{macro}[aux, EXP]{\@@_change_case_char:nN} -% \begin{macro}[aux, EXP]{\@@_change_case_char_aux:nN} +% \begin{macro}[aux, EXP] +% {\@@_change_case_char_auxi:nN, \@@_change_case_char_auxii:nN} % \begin{macro}[aux] % {\@@_lookup_lower:N, \@@_lookup_upper:N, \@@_lookup_title:N} -% \begin{macro}[aux, EXP]{\@@_change_case_cs:Nnnn} -% \begin{macro}[aux, EXP]{\@@_change_case_cs:nNnnn} -% \begin{macro}[aux, EXP]{\@@_change_case_cs_three:NNNw} -% \begin{macro}[aux, EXP]{\@@_change_case_cs_four:NNNNw} -% \begin{macro}[aux, EXP]{\@@_change_case_cs_cyr:NnNNNNw} -% \begin{macro}[aux, EXP]{\@@_change_case_cs_type:Nnnnn} -% \begin{macro}[aux, EXP]{\@@_change_case_cs_type:nnn} +% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFiix:nNN} +% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFiix:nNNN} +% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFiix:nNNNN} +% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFiix:nn} +% \begin{macro}[aux, EXP]{\@@_change_case_cs_letterlike:Nnn} +% \begin{macro}[aux, EXP]{\@@_change_case_cs_accents:NN} % \begin{macro}[aux, EXP]{\@@_change_case_cs:N} % \begin{macro}[aux, EXP]{\@@_change_case_cs:NN} % \begin{macro}[aux, EXP]{\@@_change_case_cs:NNn} @@ -3141,7 +3151,7 @@ % \begin{macrocode} \cs_new:Npn \@@_change_case_output:nwn #1#2 \@@_change_case_result:n #3 { #2 \@@_change_case_result:n { #3 #1 } } -\cs_generate_variant:Nn \@@_change_case_output:nwn { V , o , f } +\cs_generate_variant:Nn \@@_change_case_output:nwn { V , o , v , f } \cs_new:Npn \@@_change_case_end:wn #1 \@@_change_case_result:n #2 { \group_align_safe_end: @@ -3267,28 +3277,19 @@ \cs_new:Npn \@@_change_case_N_type:Nnnn #1#2#3#4 { \token_if_cs:NTF #1 -%<*initex> - { \@@_change_case_cs:N #1 } -%</initex> -%<*package> - { - \@@_change_case_cs:Nnnn #1 {#3} - { } - { \@@_change_case_cs:N #1 } - } -%</package> + { \@@_change_case_cs_letterlike:Nnn #1 {#3} { } } { \@@_change_case_char:Nnn #1 {#3} {#4} } \@@_change_case_loop:wnn #2 \q_recursion_stop {#3} {#4} } % \end{macrocode} -% For character tokens there are a couple of potential special cases to -% handle then the core idea of the loop: a lookup table. The latter uses -% the character code to spilt what would otherwise be a very long list into -% $100$ manageable blocks (this is a balance between hash table usage and -% performance). Notice that the special case code may do a look-ahead so -% requires a final \texttt{w}-type argument whereas the core lookup table -% does not and also guarantees an output so \texttt{f}-type expansion may -% be used to obtain the case-changed result. +% For character tokens there are some special cases to deal with then +% the majority of changes are covered by using the \TeX{} data as a lookup +% along with expandable character generation. This avoids needing a very +% large number of macros or (as seen in earlier versions) a somewhat tricky +% split of the characters into various blocks. Notice that the special case +% code may do a look-ahead so requires a final \texttt{w}-type argument +% whereas the core lookup table does not and also guarantees an output so +% \texttt{f}-type expansion may be used to obtain the case-changed result. % \begin{macrocode} \cs_new:Npn \@@_change_case_char:Nnn #1#2#3 { @@ -3300,18 +3301,47 @@ { \@@_change_case_char:nN {#2} #1 } } } -\cs_new:Npn \@@_change_case_char:nN #1#2 +% \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.) +% \begin{macrocode} +\cs_if_exist:NTF \utex_char:D + { + \cs_new:Npn \@@_change_case_char:nN #1#2 + { \@@_change_case_char_auxi:nN {#1} #2 } + } + { + \cs_new:Npn \@@_change_case_char:nN #1#2 + { + \int_compare:nNnTF { `#2 } > { "80 } + { + \int_compare:nNnTF { `#2 } < { "E0 } + { \@@_change_case_char_UTFiix:nNNN {#1} #2 } + { + \int_compare:nNnTF { `#2 } < { "F0 } + { \@@_change_case_char_UTFiix:nNNNN {#1} #2 } + { \@@_change_case_char_UTFiix:nNNNNN {#1} #2 } + } + } + { \@@_change_case_char_auxi:nN {#1} #2 } + } + } +\cs_new:Npn \@@_change_case_char_auxi:nN #1#2 { \@@_change_case_output:fwn { - \cs_if_exist:cTF { c__unicode_ #1 _ #2 _tl } - { \tl_use:c { c__unicode_ #1 _ #2 _tl } } - { \@@_change_case_char_aux:nN {#1} #2 } + \cs_if_exist_use:cF { c__unicode_ #1 _ \token_to_str:N #2 _tl } + { \@@_change_case_char_auxii:nN {#1} #2 } } } \cs_if_exist:NTF \utex_char:D { - \cs_new:Npn \@@_change_case_char_aux:nN #1#2 + \cs_new:Npn \@@_change_case_char_auxii:nN #1#2 { \int_compare:nNnTF { \use:c { @@_lookup_ #1 :N } #2 } = { 0 } { \exp_stop_f: #2 } @@ -3324,103 +3354,69 @@ \cs_new_eq:NN \@@_lookup_title:N \@@_lookup_upper:N } { - \cs_new:Npn \@@_change_case_char_aux:nN #1#2 { \exp_stop_f: #2 } - } -% \end{macrocode} -% If a control sequence has been given as the argument and it is not on -% the list of those with an argument to examine, the other possibility -% is that it is a character represented as a command such as |\aa|. To -% deal with that there is a need again to balance performance against -% name use. For \LaTeXe{} the list of possible special cases is quite -% long (there are around $100$ for Cyrillic alone) so a single long -% \cs{str_case:nvF} is inefficient. On the other hand, using one -% tl per special case would use a lot of names. The balance here is -% to split up the special cases by type and for Cyrillic to further -% subdivide. This works as there are various cases: -% \begin{itemize} -% \item Short (one or two letter) names for special Latin characters -% \item Cyrillic names, all starting |cyr| -% \item Greek names, all starting |text| -% \item Greek accents, all starting |acc| and only applicable -% for upper casing -% \item Other cases (\enquote{bits and pieces}) -% \end{itemize} -% Thus a split can be carried out by converting the control sequence to -% a string then examining the first four characters. For Cyrillic, the -% fourth character can be used for a second split based on the character -% code. -% -% Note that as this is dependent on \LaTeXe{}, in format mode the code -% goes straight to the final phase of handling control sequences. -% \begin{macrocode} -%<*package> -\cs_new:Npn \@@_change_case_cs:Nnnn #1#2 - { - \exp_args:Nf \@@_change_case_cs:nNnnn - { \cs_to_str:N #1 } #1 {#2} - } -\cs_new:Npn \@@_change_case_cs:nNnnn #1#2#3 - { - \tl_if_head_eq_catcode:oNTF { \use_none:nnn #1 a a a a } a - { \@@_change_case_cs_type:Nnnnn #2 { latin } {#3} } + \cs_new:Npn \@@_change_case_char_auxii:nN #1#2 { \exp_stop_f: #2 } + \cs_new:Npn \@@_change_case_char_UTFiix:nNNN #1#2#3#4 + { \@@_change_case_char_UTFiix:nnN {#1} {#2#4} #3 } + \cs_new:Npn \@@_change_case_char_UTFiix:nNNNN #1#2#3#4#5 + { \@@_change_case_char_UTFiix:nnN {#1} {#2#4#5} #3 } + \cs_new:Npn \@@_change_case_char_UTFiix:nNNNNN #1#2#3#4#5#6 + { \@@_change_case_char_UTFiix:nnN {#1} {#2#4#5#6} #3 } + \cs_new:Npn \@@_change_case_char_UTFiix:nnN #1#2#3 { - \str_if_eq_x:nnTF - { \@@_change_case_cs_three:NNNw #1 \q_nil } - { \str_if_eq:nnTF {#3} { lower } { CYR } { cyr } } - { \@@_change_case_cs_cyr:NnNNNNw #2 {#3} #1 \q_stop } + \cs_if_exist:cTF { c__unicode_ #1 _ \tl_to_str:n {#2} _tl } { - \str_if_eq_x:nnTF - { \@@_change_case_cs_three:NNNw #1 \q_nil } - { acc } - { \@@_change_case_cs_type:Nnnnn #2 { acc } {#3} } - { - \str_if_eq_x:nnTF - { \@@_change_case_cs_four:NNNNw #1 \q_nil } - { text } - { \@@_change_case_cs_type:Nnnnn #2 { greek } {#3} } - { \@@_change_case_cs_type:Nnnnn #2 { misc } {#3} } - } + \@@_change_case_output:vwn + { c__unicode_ #1 _ \tl_to_str:n {#2} _tl } } + { \@@_change_case_output:nwn {#2} } + #3 } } -\cs_new:Npn \@@_change_case_cs_three:NNNw #1#2#3#4 \q_nil { #1#2#3 } -\cs_new:Npn \@@_change_case_cs_four:NNNNw #1#2#3#4#5 \q_nil { #1#2#3#4 } -\cs_new:Npn \@@_change_case_cs_cyr:NnNNNNw #1#2#3#4#5#6#7 \q_stop +% \end{macrocode} +% Before dealing with general control sequences there are the special +% ones to deal with. Letter-like control sequences are a simple look-up, +% while for accents the loop is much as done elsewhere. Notice that +% we have a no-op test to make sure there is no unexpected expansion of +% letter-like input. The third argument here is needed for mixed casing, +% where it if there is a hit there has to be a change-of-path. +% \begin{macrocode} +\cs_new:Npn \@@_change_case_cs_letterlike:Nnn #1#2#3 { - \@@_change_case_cs_type:Nnnnn #1 - { cyrillic } + \cs_if_exist:cTF { c_@@_change_case_ #2 _ \token_to_str:N #1 _tl } { - #2 _ - \int_to_roman:n - { - 1 + - \int_div_truncate:nn - { - `#6 - \str_if_eq:nnTF {#2} { lower } { `A } { `a } - } - { 7 } - } + \@@_change_case_output:vwn + { c_@@_change_case_ #2 _ \token_to_str:N #1 _tl } + #3 } - } -\cs_new:Npn \@@_change_case_cs_type:Nnnnn #1#2#3 - { - \exp_args:Nf \@@_change_case_cs_type:nnn { - \str_case:nvF #1 - { c_@@_change_case_ #2 _ #3 _ tl } - { \exp_stop_f: } + \cs_if_exist:cTF + { + c_@@_change_case_ + \str_if_eq:nnTF {#2} { lower } { upper } { lower } + _ \token_to_str:N #1 _tl + } + { + \@@_change_case_output:nwn {#1} + #3 + } + { + \exp_after:wN \@@_change_case_cs_accents:NN + \exp_after:wN #1 \l_tl_case_change_accents_tl + \q_recursion_tail \q_recursion_stop + } } } -\cs_new:Npn \@@_change_case_cs_type:nnn #1#2#3 +\cs_new:Npn \@@_change_case_cs_accents:NN #1#2 { - \tl_if_blank:nTF {#1} - {#3} + \quark_if_recursion_tail_stop_do:Nn #2 + { \@@_change_case_cs:N #1 } + \str_if_eq:nnTF {#1} {#2} { - \@@_change_case_output:nwn {#1} - #2 + \use_i_delimit_by_q_recursion_stop:nw + { \@@_change_case_output:nwn {#1} } } + { \@@_change_case_cs_accents:NN #1 } } -%</package> % \end{macrocode} % To deal with a control sequence there is first a need to test if it is % on the list which indicate that case changing should be skipped. That's @@ -3517,7 +3513,6 @@ % \end{macro} % \end{macro} % \end{macro} -% \end{macro} % % \begin{macro}[aux, EXP]{\@@_change_case_lower_sigma:Nnw} % \begin{macro}[aux, EXP]{\@@_change_case_lower_sigma:w} @@ -3577,16 +3572,18 @@ % either a dotless-I or a dotted-I. In the latter case the mapping is % easy, but in the former there is a second stage search. % \begin{macrocode} -\cs_new:Npn \@@_change_case_lower_tr:Nnw #1#2 +\cs_if_exist:NTF \utex_char:D { - \int_compare:nNnTF { `#1 } = { "0049 } - { \@@_change_case_lower_tr_auxi:Nw } + \cs_new:Npn \@@_change_case_lower_tr:Nnw #1#2 { - \int_compare:nNnTF { `#1 } = { "0130 } - { \@@_change_case_output:nwn { i } } - {#2} + \int_compare:nNnTF { `#1 } = { "0049 } + { \@@_change_case_lower_tr_auxi:Nw } + { + \int_compare:nNnTF { `#1 } = { "0130 } + { \@@_change_case_output:nwn { i } } + {#2} + } } - } % \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 @@ -3595,30 +3592,61 @@ % (it grabs \cs{@@_change_case_loop:wn} and the dot-above char and % discards the latter). % \begin{macrocode} -\cs_new:Npn \@@_change_case_lower_tr_auxi:Nw #1#2 \q_recursion_stop - { - \tl_if_head_is_N_type:nTF {#2} - { \@@_change_case_lower_tr_auxii:Nw #2 \q_recursion_stop } - { \@@_change_case_output:Vwn \c__unicode_dotless_i_tl } - #1 #2 \q_recursion_stop - } -\cs_new:Npn \@@_change_case_lower_tr_auxii:Nw #1#2 \q_recursion_stop - { - \@@_change_case_if_expandable:NTF #1 + \cs_new:Npn \@@_change_case_lower_tr_auxi:Nw #1#2 \q_recursion_stop { - \exp_after:wN \@@_change_case_lower_tr_auxi:Nw #1 - #2 \q_recursion_stop + \tl_if_head_is_N_type:nTF {#2} + { \@@_change_case_lower_tr_auxii:Nw #2 \q_recursion_stop } + { \@@_change_case_output:Vwn \c__unicode_dotless_i_tl } + #1 #2 \q_recursion_stop } + \cs_new:Npn \@@_change_case_lower_tr_auxii:Nw #1#2 \q_recursion_stop { - \bool_if:nTF + \@@_change_case_if_expandable:NTF #1 + { + \exp_after:wN \@@_change_case_lower_tr_auxi:Nw #1 + #2 \q_recursion_stop + } { - \token_if_cs_p:N #1 - || ! ( \int_compare_p:nNn { `#1 } = { "0307 } ) + \bool_if:nTF + { + \token_if_cs_p:N #1 + || ! ( \int_compare_p:nNn { `#1 } = { "0307 } ) + } + { \@@_change_case_output:Vwn \c__unicode_dotless_i_tl } + { + \@@_change_case_output:nwn { i } + \use_i:nn + } } + } + } +% \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. +% \begin{macrocode} + { + \cs_new:Npn \@@_change_case_lower_tr:Nnw #1#2 + { + \int_compare:nNnTF { `#1 } = { "0049 } { \@@_change_case_output:Vwn \c__unicode_dotless_i_tl } { + \int_compare:nNnTF { `#1 } = { 196 } + { \@@_change_case_lower_tr_auxi:Nw #1 {#2} } + {#2} + } + } + \cs_new:Npn \@@_change_case_lower_tr_auxi:Nw #1#2#3#4 + { + \int_compare:nNnTF { `#4 } = { 176 } + { \@@_change_case_output:nwn { i } - \use_i:nn + #3 + } + { + #2 + #3 #4 } } } @@ -3792,30 +3820,87 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\__tl_change_case_upper_de-alt:Nnw} +% \begin{macro}{\@@_change_case_upper_de-alt:Nnw} % A simple alternative version for German. % \begin{macrocode} \cs_new:cpn { @@_change_case_upper_de-alt:Nnw } #1#2 { \int_compare:nNnTF { `#1 } = { 223 } - { \__tl_change_case_output:Vwn \c__unicode_upper_Eszett_tl } + { \@@_change_case_output:Vwn \c__unicode_upper_Eszett_tl } {#2} } % \end{macrocode} % \end{macro} % +% \begin{macro}[EXP, int]{\__unicode_codepoint_to_UTFiix:n} +% \begin{macro}[EXP, aux]{\__unicode_codepoint_to_UTFiix_auxi:n} +% \begin{macro}[EXP, aux]{\__unicode_codepoint_to_UTFiix_auxii:Nnn} +% \begin{macro}[EXP, aux]{\__unicode_codepoint_to_UTFiix_auxiii:n} +% This code will convert a codepoint into the correct UTF-8 represenation. +% As there are a variable number of octets, the result starts with the +% numeral |1|--|4| to indicate the nature of the returned value. Note that +% this code will cover the full range even though at this stage it is not +% required here. Also note that longer-term this is likely to need a public +% interface and/or moving to \pkg{l3str} (see experimental string +% conversions). In terms of the algoritm itself, see +% \url{https://en.wikipedia.org/wiki/UTF-8} for the octet pattern. +% \begin{macrocode} +\cs_new:Npn \__unicode_codepoint_to_UTFiix:n #1 + { + \exp_args:Nf \__unicode_codepoint_to_UTFiix_auxi:n + { \int_eval:n {#1} } + } +\cs_new:Npn \__unicode_codepoint_to_UTFiix_auxi:n #1 + { + \if_int_compare:w #1 > "80 ~ + \if_int_compare:w #1 < "800 ~ + 2 + \__unicode_codepoint_to_UTFiix_auxii:Nnn C {#1} { 64 } + \__unicode_codepoint_to_UTFiix_auxiii:n {#1} + \else: + \if_int_compare:w #1 < "10000 ~ + 3 + \__unicode_codepoint_to_UTFiix_auxii:Nnn E {#1} { 64 * 64 } + \__unicode_codepoint_to_UTFiix_auxiii:n {#1} + \__unicode_codepoint_to_UTFiix_auxiii:n + { \int_div_truncate:nn {#1} { 64 } } + \else: + 4 + \__unicode_codepoint_to_UTFiix_auxii:Nnn F + {#1} { 64 * 64 * 64 } + \__unicode_codepoint_to_UTFiix_auxiii:n + { \int_div_truncate:nn {#1} { 64 * 64 } } + \__unicode_codepoint_to_UTFiix_auxiii:n + { \int_div_truncate:nn {#1} { 64 } } + \__unicode_codepoint_to_UTFiix_auxiii:n {#1} + + \fi: + \fi: + \else: + 1 {#1} + \fi: + } +\cs_new:Npn \__unicode_codepoint_to_UTFiix_auxii:Nnn #1#2#3 + { { \int_eval:n { "#10 + \int_div_truncate:nn {#2} {#3} } } } +\cs_new:Npn \__unicode_codepoint_to_UTFiix_auxiii:n #1 + { { \int_eval:n { \int_mod:nn {#1} { 64 } + 128 } } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % \begin{variable} % { % \c__unicode_std_sigma_tl , % \c__unicode_final_sigma_tl , % \c__unicode_accents_lt_tl , % \c__unicode_dot_above_tl , -% \c__unicode_dotless_i_tl , -% \c__unicode_dotted_I_tl , -% \c__unicode_i_ogonek_tl , -% \c__unicode_I_ogonek_tl , % \c__unicode_upper_Eszett_tl % } +% The above needs various special token lists containg pre-formed characters. +% This set are only available in Unicode engines, with no-op definitions +% for $8$-bit use. % \begin{macrocode} \cs_if_exist:NTF \utex_char:D { @@ -3831,25 +3916,264 @@ { \utex_char:D "0069 ~ \utex_char:D "0307 ~ \utex_char:D "0303 ~ } } \tl_const:Nx \c__unicode_dot_above_tl { \utex_char:D "0307 ~ } - \tl_const:Nx \c__unicode_dotless_i_tl { \utex_char:D "0131 ~ } - \tl_const:Nx \c__unicode_dotted_I_tl { \utex_char:D "0130 ~ } - \tl_const:Nx \c__unicode_i_ogonek_tl { \utex_char:D "012F ~ } - \tl_const:Nx \c__unicode_I_ogonek_tl { \utex_char:D "012E ~ } \tl_const:Nx \c__unicode_upper_Eszett_tl { \utex_char:D "1E9E ~} } { - \tl_const:Nn \c__unicode_std_sigma_tl { } - \tl_const:Nn \c__unicode_final_sigma_tl { } - \tl_const:Nn \c__unicode_accents_lt_tl { } - \tl_const:Nn \c__unicode_dot_above_tl { } - \tl_const:Nn \c__unicode_dotless_i_tl { I } - \tl_const:Nn \c__unicode_dotted_I_tl { i } - \tl_const:Nn \c__unicode_i_ogonek_tl { } - \tl_const:Nn \c__unicode_I_ogonek_tl { } - \tl_const:Nn \c__unicode_upper_Eszett_tl { } + \tl_const:Nn \c__unicode_std_sigma_tl { } + \tl_const:Nn \c__unicode_final_sigma_tl { } + \tl_const:Nn \c__unicode_accents_lt_tl { } + \tl_const:Nn \c__unicode_dot_above_tl { } + \tl_const:Nn \c__unicode_upper_Eszett_tl { } } % \end{macrocode} % \end{variable} +% \begin{variable} +% { +% \c__unicode_dotless_i_tl , +% \c__unicode_dotted_I_tl , +% \c__unicode_i_ogonek_tl , +% \c__unicode_I_ogonek_tl , +% } +% For cases where there is an $8$-bit option in the |T1| font set up, +% a variant is provided in both cases. +% \begin{macrocode} +\group_begin: + \cs_if_exist:NTF \utex_char:D + { + \cs_set_protected:Npn \@@_tmp:w #1#2 + { \tl_const:Nx #1 { \utex_char:D "#2 ~ } } + } + { + \char_set_catcode_active:N . + \char_set_catcode_active:N ! + \cs_set_protected:Npn \@@_tmp:w #1#2 + { + \group_begin: + \cs_set_protected:Npn \@@_tmp:w ##1##2##3 + { + \char_set_lccode:nn { `\. } {##2} + \char_set_lccode:nn { `\! } {##3} + \tex_lowercase:D + { \tl_const:Nn #1 { . ! } } + } + \tl_set:Nx \l_@@_internal_a_tl + { \__unicode_codepoint_to_UTFiix:n {"#2} } + \exp_after:wN \@@_tmp:w \l_@@_internal_a_tl + \group_end: + } + } + \@@_tmp:w \c__unicode_dotless_i_tl { 0131 } + \@@_tmp:w \c__unicode_dotted_I_tl { 0130 } + \@@_tmp:w \c__unicode_i_ogonek_tl { 012F } + \@@_tmp:w \c__unicode_I_ogonek_tl { 012E } +\group_end: +% \end{macrocode} +% \end{variable} +% +% For $8$-bit engines we now need to define the case-change data for +% the multi-octet mappings. These need a list of what code points are +% doable in |T1| so the list is hard coded (there's no saving in loading +% the mappings dynamically). All of the straight-forward ones have two +% octets, so that is taken as read. +% \begin{macrocode} +\group_begin: + \char_set_catcode_active:N . + \char_set_catcode_active:N ! + \char_set_catcode_active:N ; + \char_set_catcode_active:N , + \bool_if:nT + { + \sys_if_engine_pdftex_p: || \sys_if_engine_uptex_p: + } + { + \cs_set_protected:Npn \@@_loop:nn #1#2 + { + \quark_if_recursion_tail_stop:n {#1} + \tl_set:Nx \l_@@_internal_a_tl + { + \__unicode_codepoint_to_UTFiix:n {"#1} + \__unicode_codepoint_to_UTFiix:n {"#2} + } + \exp_after:wN \@@_tmp:w \l_@@_internal_a_tl + \@@_loop:nn + } + \cs_set_protected:Npn \@@_tmp:w #1#2#3#4#5#6 + { + \char_set_lccode:nn { `\. } {#2} + \char_set_lccode:nn { `\! } {#3} + \char_set_lccode:nn { `\; } {#5} + \char_set_lccode:nn { `\, } {#6} + \tex_lowercase:D + { + \tl_const:cn { c__unicode_lower_ \tl_to_str:n { . ! } _tl } + { ; , } + \tl_const:cn { c__unicode_upper_ \tl_to_str:n { ; , } _tl } + { . ! } + } + } + \@@_loop:nn + { 00C0 } { 00E0 } + { 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 } + { 01CD } { 01CE } + { 01CF } { 01D0 } + { 01D1 } { 01D2 } + { 01D3 } { 01D4 } + { 01E2 } { 01E3 } + { 01E6 } { 01E7 } + { 01E8 } { 01E9 } + { 01EA } { 01EB } + { 01F4 } { 01F5 } + { 0218 } { 0219 } + { 021A } { 021B } + \q_recursion_tail ? + \q_recursion_stop + \cs_set_protected:Npn \@@_tmp:w #1#2#3 + { + \group_begin: + \cs_set_protected:Npn \@@_tmp:w ##1##2##3 + { + \char_set_lccode:nn { `\. } {##2} + \char_set_lccode:nn { `\! } {##3} + \tex_lowercase:D + { + \tl_const:cn + { c__unicode_ #3 _ \tl_to_str:n { . ! } _tl } + } + { #2 } + } + \tl_set:Nx \l_@@_internal_a_tl + { \__unicode_codepoint_to_UTFiix:n { "#1 } } + \exp_after:wN \@@_tmp:w \l_@@_internal_a_tl + \group_end: + } + \@@_tmp:w { 00DF } { SS } { upper } + \@@_tmp:w { 00DF } { Ss } { title } + \@@_tmp:w { 0131 } { I } { upper } + } + \group_end: +% \end{macrocode} +% +% The (fixed) look-up mappings for letter-like control sequences. +% \begin{macrocode} +\group_begin: + \cs_set_protected:Npn \@@_change_case_setup:NN #1#2 + { + \quark_if_recursion_tail_stop:N #1 + \tl_const:cn { c_@@_change_case_lower_ \token_to_str:N #1 _tl } { #2 } + \tl_const:cn { c_@@_change_case_upper_ \token_to_str:N #2 _tl } { #1 } + \@@_change_case_setup:NN + } + \@@_change_case_setup:NN + \AA \aa + \AE \ae + \DH \dh + \DJ \dj + \L \l + \NG \ng + \O \o + \OE \oe + \SS \ss + \TH \th + \q_recursion_tail ? + \q_recursion_stop + \tl_const:cn { c_@@_change_case_upper_ \token_to_str:N \i _tl } { I } + \tl_const:cn { c_@@_change_case_upper_ \token_to_str:N \j _tl } { J } +\group_end: +% \end{macrocode} +% +% \begin{variable}{\l_tl_case_change_accents_tl} +% A list of accents to leave alone. +% \begin{macrocode} +\tl_new:N \l_tl_case_change_accents_tl +\tl_set:Nn \l_tl_case_change_accents_tl { \" \^ \' \` \. \c \u \~ \H \v } +% \end{macrocode} +% \end{variable} % % \begin{macro}[aux, EXP]{\@@_mixed_case:nn} % \begin{macro}[aux, EXP]{\@@_mixed_case_aux:nn} @@ -3859,6 +4183,7 @@ % \begin{macro}[aux, EXP]{\@@_mixed_case_N_type:Nwn} % \begin{macro}[aux, EXP]{\@@_mixed_case_N_type:NNNnn} % \begin{macro}[aux, EXP]{\@@_mixed_case_N_type:Nnn} +% \begin{macro}[aux, EXP]{\@@_mixed_case_letterlike:Nw} % \begin{macro}[aux, EXP]{\@@_mixed_case_char:N} % \begin{macro}[aux, EXP]{\@@_mixed_case_skip:N} % \begin{macro}[aux, EXP]{\@@_mixed_case_skip:NN} @@ -3950,34 +4275,24 @@ % \end{macrocode} % The business end of the loop is here: there is first a need to deal % with any control sequence cases before looking for characters to skip. +% If there is a hit for a letter-like control sequence, switch to lower +% casing. % \begin{macrocode} \cs_new:Npn \@@_mixed_case_N_type:Nnn #1#2#3 { \token_if_cs:NTF #1 -%<*initex> { - \@@_change_case_cs:N #1 + \@@_change_case_cs_letterlike:Nnn #1 { upper } + { \@@_mixed_case_letterlike:Nw } \@@_mixed_case_loop:wn #2 \q_recursion_stop {#3} } -%</initex> -%<*package> - { - \@@_change_case_cs:Nnnn #1 { upper } - { - \@@_change_case_loop:wnn - #2 \q_recursion_stop { lower } {#3} - } - { - \@@_change_case_cs:N #1 - \@@_mixed_case_loop:wn #2 \q_recursion_stop {#3} - } - } -%</package> { \@@_mixed_case_char:Nn #1 {#3} \@@_change_case_loop:wnn #2 \q_recursion_stop { lower } {#3} } } +\cs_new:Npn \@@_mixed_case_letterlike:Nw #1#2 \q_recursion_stop + { \@@_change_case_loop:wnn #2 \q_recursion_stop { lower } } % \end{macrocode} % As detailed above, handling a mixed case char means first looking for % exceptions then treating as an upper cased letter, but with a list of @@ -4040,6 +4355,7 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}[aux, EXP]{\@@_change_case_mixed_nl:Nnw} % \begin{macro}[aux, EXP]{\@@_change_case_mixed_nl:Nw} @@ -4135,286 +4451,6 @@ % \end{macrocode} % \end{variable} % -% \begin{variable} -% { -% \c_@@_change_case_latin_upper_tl , -% \c_@@_change_case_latin_lower_tl , -% \c_@@_change_case_cyrillic_upper_i_tl , -% \c_@@_change_case_cyrillic_upper_ii_tl , -% \c_@@_change_case_cyrillic_upper_iii_tl , -% \c_@@_change_case_cyrillic_upper_iv_tl , -% \c_@@_change_case_cyrillic_lower_i_tl , -% \c_@@_change_case_cyrillic_lower_ii_tl , -% \c_@@_change_case_cyrillic_lower_iii_tl , -% \c_@@_change_case_cyrillic_lower_iv_tl , -% \c_@@_change_case_greek_upper_tl , -% \c_@@_change_case_greek_lower_tl , -% \c_@@_change_case_acc_upper_tl , -% \c_@@_change_case_acc_upper_tl , -% \c_@@_change_case_misc_upper_tl , -% \c_@@_change_case_misc_lower_tl -% } -% The data for case changing control sequences representing characters -% is stored such that further expansion is inhibited. This is required -% as many of the \LaTeXe{} commands are fragile and so will fail inside -% an \texttt{x}-type expansion without this precaution. As such, there is -% a bit of set up to deal with the various requirements here: upper and -% lower case mappings are not identical so special end cases are needed -% to get everything set up correctly with minimal repetition. -% \begin{macrocode} -%<*package> -\group_begin: - \cs_set_protected:Npn \@@_change_case_setup:nnnn #1#2#3#4 - { - \tl_const:cx { c_@@_change_case_ #1 _upper #2 _tl } - { - \@@_change_case_map:NN - #3 \q_recursion_tail ? \q_recursion_stop - } - \tl_const:cx { c_@@_change_case_ #1 _lower #2 _tl } - { - \@@_change_case_map:NNN #4 - #3 \q_recursion_tail ? \q_recursion_stop - } - } - \cs_set:Npn \@@_change_case_map:NN #1#2 - { - \quark_if_recursion_tail_stop:N #1 - \exp_not:N #1 \exp_not:n { { \exp_stop_f: #2 } } - \@@_change_case_map:NN - } - \cs_set:Npn \@@_change_case_map:NNN #1#2#3 - { - \str_if_eq:nnT {#1} {#2} - { \use_none_delimit_by_q_recursion_stop:w } - \exp_not:N #3 \exp_not:n { { \exp_stop_f: #2 } } - \@@_change_case_map:NNN #1 - } - \@@_change_case_setup:nnnn - { latin } - { } - { - \aa \AA - \ae \AE - \dh \DH - \dj \DJ - \l \L - \ng \NG - \o \O - \oe \OE - \ss \SS - \th \TH - \i I - \j J - } - { \i } - \@@_change_case_setup:nnnn - { cyrillic } - { _i } - { - \cyra \CYRA - \cyrabhch \CYRABHCH - \cyrabhchdsc \CYRABHCHDSC - \cyrabhdze \CYRABHDZE - \cyrabhha \CYRABHHA - \cyrae \CYRAE - \cyrb \CYRB - \cyrbyus \CYRBYUS - \cyrc \CYRC - \cyrch \CYRCH - \cyrchldsc \CYRCHLDSC - \cyrchrdsc \CYRCHRDSC - \cyrchvcrs \CYRCHVCRS - \cyrd \CYRD - \cyrdelta \CYRDELTA - \cyrdje \CYRDJE - \cyrdze \CYRDZE - \cyrdzhe \CYRDZHE - \cyre \CYRE - \cyreps \CYREPS - \cyrerev \CYREREV - \cyrery \CYRERY - \cyrf \CYRF - \cyrfita \CYRFITA - \cyrg \CYRG - \cyrgdsc \CYRGDSC - \cyrgdschcrs \CYRGDSCHCRS - \cyrghcrs \CYRGHCRS - \cyrghk \CYRGHK - \cyrgup \CYRGUP - } - { \q_recursion_tail } - \@@_change_case_setup:nnnn - { cyrillic } - { _ii } - { - \cyrh \CYRH - \cyrhdsc \CYRHDSC - \cyrhhcrs \CYRHHCRS - \cyrhhk \CYRHHK - \cyrhrdsn \CYRHRDSN - \cyri \CYRI - \cyrie \CYRIE - \cyrii \CYRII - \cyrishrt \CYRISHRT - \cyrishrtdsc \CYRISHRTDSC - \cyrizh \CYRIZH - \cyrje \CYRJE - \cyrk \CYRK - \cyrkbeak \CYRKBEAK - \cyrkdsc \CYRKDSC - \cyrkhcrs \CYRKHCRS - \cyrkhk \CYRKHK - \cyrkvcrs \CYRKVCRS - \cyrl \CYRL - \cyrldsc \CYRLDSC - \cyrlhk \CYRLHK - \cyrlje \CYRLJE - \cyrm \CYRM - \cyrmdsc \CYRMDSC - \cyrmhk \CYRMHK - \cyrn \CYRN - \cyrndsc \CYRNDSC - \cyrng \CYRNG - \cyrnhk \CYRNHK - \cyrnje \CYRNJE - \cyrnlhk \CYRNLHK - } - { \q_recursion_tail } - \@@_change_case_setup:nnnn - { cyrillic } - { _iii } - { - \cyro \CYRO - \cyrotld \CYROTLD - \cyrp \CYRP - \cyrphk \CYRPHK - \cyrq \CYRQ - \cyrr \CYRR - \cyrrdsc \CYRRDSC - \cyrrhk \CYRRHK - \cyrrtick \CYRRTICK - \cyrs \CYRS - \cyrsacrs \CYRSACRS - \cyrschwa \CYRSCHWA - \cyrsdsc \CYRSDSC - \cyrsemisftsn \CYRSEMISFTSN - \cyrsftsn \CYRSFTSN - \cyrsh \CYRSH - \cyrshch \CYRSHCH - \cyrshha \CYRSHHA - \cyrt \CYRT - \cyrtdsc \CYRTDSC - \cyrtetse \CYRTETSE - \cyrtshe \CYRTSHE - \cyru \CYRU - \cyrushrt \CYRUSHRT - } - { \q_recursion_tail } - \@@_change_case_setup:nnnn - { cyrillic } - { _iv } - { - \cyrv \CYRV - \cyrw \CYRW - \cyry \CYRY - \cyrya \CYRYA - \cyryat \CYRYAT - \cyryhcrs \CYRYHCRS - \cyryi \CYRYI - \cyryo \CYRYO - \cyryu \CYRYU - \cyrz \CYRZ - \cyrzdsc \CYRZDSC - \cyrzh \CYRZH - \cyrzhdsc \CYRZHDSC - } - { \q_recursion_tail } - \@@_change_case_setup:nnnn - { greek } - { } - { - \textalpha \textAlpha - \textbeta \textBeta - \textchi \textChi - \textdelta \textDelta - \textdigamma \textDigamma - \texteta \textEta - \textepsilon \textEpsilon - \textgamma \textGamma - \textiota \textIota - \textkappa \textKappa - \textlambda \textLambda - \textmu \textMu - \textnu \textNu - \textomega \textOmega - \textomicron \textOmicron - \textphi \textPhi - \textpi \textPi - \textpsi \textPsi - \textqoppa \textQoppa - \textrho \textRho - \textsampi \textSampi - \textautosigma \textSigma - \textstigma \textStigma - \texttheta \textTheta - \texttau \textTau - \textupsilon \textUpsilon - \textxi \textXi - \textzeta \textZeta - \textsigma \textSigma - \textvarsigma \textSigma - \textvarstigma \textStigma - } - { \textsigma } - \tl_const:Nn \c_@@_change_case_acc_upper_tl - { - \accdasia { \exp_stop_f: \LGR@accdropped } - \accdasiaoxia { \exp_stop_f: \LGR@hiatus } - \accdasiavaria { \exp_stop_f: \LGR@accdropped } - \accdasiaperispomeni { \exp_stop_f: \LGR@accdropped } - \accpsili { \exp_stop_f: \LGR@hiatus } - \accpsilioxia { \exp_stop_f: \LGR@hiatus } - \accpsilivaria { \exp_stop_f: \LGR@hiatus } - \accpsiliperispomeni { \exp_stop_f: \LGR@accdropped } - \acctonos { \exp_stop_f: \LGR@hiatus } - \accvaria { \exp_stop_f: \LGR@accdropped } - \accdialytikatonos { \exp_stop_f: \LGR@accDialytika } - \accdialytikavaria { \exp_stop_f: \LGR@accDialytika } - \accdialytikaperispomeni { \exp_stop_f: \LGR@accDialytika } - \accperispomeni { \exp_stop_f: \LGR@accdropped } - } - \tl_const:Nn \c_@@_change_case_acc_lower_tl { } - \tl_const:Nn \c_@@_change_case_misc_upper_tl - { - \ypogegrammeni { \exp_stop_f: \prosgegrammeni } - \abreve { \exp_stop_f: \Abreve } - \acircumflex { \exp_stop_f: \Acircumflex } - \ecircumflex { \exp_stop_f: \Ecircumflex } - \ocircumflex { \exp_stop_f: \Ocircumflex } - \ohorn { \exp_stop_f: \Ohorn } - \uhorn { \exp_stop_f: \Uhorn } - } - \tl_const:Nn \c_@@_change_case_misc_lower_tl - { - \prosgegrammeni { \exp_stop_f: \ypogegrammeni } - \Abreve { \exp_stop_f: \abreve } - \Acircumflex { \exp_stop_f: \acircumflex } - \Ecircumflex { \exp_stop_f: \ecircumflex } - \Ocircumflex { \exp_stop_f: \ocircumflex } - \Ohorn { \exp_stop_f: \ohorn } - \Uhorn { \exp_stop_f: \uhorn } - \ABREVE { \exp_stop_f: \abreve } - \ACIRCUMFLEX { \exp_stop_f: \acircumflex } - \ECIRCUMFLEX { \exp_stop_f: \ecircumflex } - \OCIRCUMFLEX { \exp_stop_f: \ocircumflex } - \OHORN { \exp_stop_f: \ohorn } - \UHORN { \exp_stop_f: \uhorn } - } -\group_end: -%</package> -% \end{macrocode} -% \end{variable} % % \begin{macro}{\tl_log:N, \tl_log:c} % Redirect output of \cs{tl_show:N} to the log. |