summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2017-07-15 21:27:01 +0000
committerKarl Berry <karl@freefriends.org>2017-07-15 21:27:01 +0000
commitb1ce47fe4d0e1f06d1b019c3c6eb5f1b0ecd5e14 (patch)
tree58362abe4b603bb5f6db898b9b835bc8af730b3e /Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
parent03b8dcfa3435f0265dfad4fd09aaab8f4ff9c617 (diff)
l3 (15jul17)
git-svn-id: svn://tug.org/texlive/trunk@44813 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx726
1 files changed, 441 insertions, 285 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
index aeb2ce1469b..e8f04f06024 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
@@ -42,7 +42,7 @@
% }^^A
% }
%
-% \date{Released 2017/05/29}
+% \date{Released 2017/07/15}
%
% \maketitle
%
@@ -82,6 +82,51 @@
% into the kernel. However, real use sometimes leads to better ideas, so functions from this module are
% \textbf{not necessarily stable} and we may have to adjust them!
%
+% \section{Additions to \pkg{l3basics}}
+%
+% \begin{function}[added = 2017-07-14]
+% {\debug_check_declarations_on:, \debug_check_declarations_off:}
+% \begin{syntax}
+% \cs{debug_check_declarations_on:}
+% \cs{debug_check_declarations_off:}
+% \end{syntax}
+% Turn on and off within a group the code that checks that all
+% \pkg{expl3} variables used were previously declared, as done
+% globally by the \texttt{check-declarations} option. This can only
+% be used if \pkg{expl3} is loaded with one of the options
+% \texttt{check-declarations}, \texttt{log-functions}, or
+% \texttt{enable-debug}.
+% \end{function}
+%
+% \begin{function}[added = 2017-07-14]
+% {\debug_log_functions_on:, \debug_log_functions_off:}
+% \begin{syntax}
+% \cs{debug_log_functions_on:}
+% \cs{debug_log_functions_off:}
+% \end{syntax}
+% Turn on and off within a group the code that logs function
+% definitions, as done globally by the \texttt{log-functions} option.
+% This can only be used if \pkg{expl3} is loaded with one of the
+% options \texttt{check-declarations}, \texttt{log-functions}, or
+% \texttt{enable-debug}.
+% \end{function}
+%
+% \begin{function}[added = 2017-07-04]{\mode_leave_vertical:}
+% \begin{syntax}
+% \cs{mode_leave_vertical:}
+% \end{syntax}
+% Ensures that \TeX{} is not in vertical (inter-paragraph) mode. In
+% horizontal or math mode this command has no effect, in vertical mode it
+% switches to horizontal mode, and inserts a box of width
+% \tn{parindent}, followed by the \tn{everypar} token list.
+% \begin{texnote}
+% This results in the contents of the \tn{everypar} token register being
+% inserted, after \cs{mode_leave_vertical:} is complete. Notice that in
+% contrast to the \LaTeXe{} \tn{leavevmode} approach, no box is used
+% by the method implemented here.
+% \end{texnote}
+% \end{function}
+%
% \section{Additions to \pkg{l3box}}
%
% \subsection{Viewing part of a box}
@@ -91,11 +136,11 @@
% \cs{box_clip:N} \meta{box}
% \end{syntax}
% Clips the \meta{box} in the output so that only material inside the
-% bounding box is displayed in the output. The updated \meta{box} will be an
+% bounding box is displayed in the output. The updated \meta{box} is an
% hbox, irrespective of the nature of the \meta{box} before the clipping is
% applied. The clipping applies within the current \TeX{} group level.
%
-% \textbf{These functions require the \LaTeX3 native drivers: they will
+% \textbf{These functions require the \LaTeX3 native drivers: they do
% not work with the \LaTeXe{} \pkg{graphics} drivers!}
%
% \begin{texnote}
@@ -113,9 +158,9 @@
% Adjusts the bounding box of the \meta{box} \meta{left} is removed from
% the left-hand edge of the bounding box, \meta{right} from the right-hand
% edge and so fourth. All adjustments are \meta{dimension expressions}.
-% Material output of the bounding box will still be displayed in the output
+% Material outside of the bounding box is still displayed in the output
% unless \cs{box_clip:N} is subsequently applied.
-% The updated \meta{box} will be an
+% The updated \meta{box} is an
% hbox, irrespective of the nature of the \meta{box} before the trim
% operation is applied. The adjustment applies within the current \TeX{}
% group level. The behavior of the operation where the trims requested is
@@ -129,10 +174,10 @@
% Adjusts the bounding box of the \meta{box} such that it has lower-left
% co-ordinates (\meta{llx}, \meta{lly}) and upper-right co-ordinates
% (\meta{urx}, \meta{ury}). All four co-ordinate positions are
-% \meta{dimension expressions}. Material output of the bounding box will
-% still be displayed in the output unless \cs{box_clip:N} is
+% \meta{dimension expressions}. Material outside of the bounding box is
+% still displayed in the output unless \cs{box_clip:N} is
% subsequently applied.
-% The updated \meta{box} will be an
+% The updated \meta{box} is an
% hbox, irrespective of the nature of the \meta{box} before the viewport
% operation is applied. The adjustment applies within the current \TeX{}
% group level.
@@ -152,7 +197,7 @@
% \begin{texnote}
% The result is returned within the \tn{unexpanded}
% primitive (\cs{exp_not:n}), which means that the \meta{item}
-% will not expand further when appearing in an \texttt{x}-type
+% does not expand further when appearing in an \texttt{x}-type
% argument expansion.
% \end{texnote}
% \end{function}
@@ -172,8 +217,8 @@
% \cs{coffin_rotate:Nn} \meta{coffin} \Arg{angle}
% \end{syntax}
% Rotates the \meta{coffin} by the given \meta{angle} (given in
-% degrees counter-clockwise). This process will rotate both the
-% coffin content and poles. Multiple rotations will not result in
+% degrees counter-clockwise). This process rotates both the
+% coffin content and poles. Multiple rotations do not result in
% the bounding box of the coffin growing unnecessarily.
% \end{function}
%
@@ -188,6 +233,46 @@
%
% \section{Additions to \pkg{l3file}}
%
+% \begin{function}[added = 2017-07-11]{\file_get_mdfive_hash:nN}
+% \begin{syntax}
+% \cs{file_get_mdfive_hash:nN} \Arg{file name} \meta{str var}
+% \end{syntax}
+% Searches for \meta{file name} using the current \TeX{} search
+% path and the additional paths controlled by \cs{file_path_include:n}.
+% If found, sets the \meta{str var} to the MD5 sum generated from the
+% content of the file.
+% Where the file is not found, the \meta{str var} will be empty.
+% \end{function}
+%
+% \begin{function}[added = 2017-07-09]{\file_get_size:nN}
+% \begin{syntax}
+% \cs{file_get_size:nN} \Arg{file name} \meta{str var}
+% \end{syntax}
+% Searches for \meta{file name} using the current \TeX{} search
+% path and the additional paths controlled by \cs{file_path_include:n}.
+% If found, sets the \meta{str var} to the size of the file in bytes.
+% Where the file is not found, the \meta{str var} will be empty.
+% \begin{texnote}
+% The \XeTeX{} engine provides no way to implement this function.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}[added = 2017-07-09]{\file_get_timestamp:nN}
+% \begin{syntax}
+% \cs{file_get_timestamp:nN} \Arg{file name} \meta{str var}
+% \end{syntax}
+% Searches for \meta{file name} using the current \TeX{} search
+% path and the additional paths controlled by \cs{file_path_include:n}.
+% If found, sets the \meta{str var} to the modification timestamp of
+% the file in the form |D:|\meta{year}\meta{month}\meta{day}\meta{hour}^^A
+% \meta{minute}\meta{second}\meta{offset}, where the latter may be |Z|
+% (UTC) or \meta{plus-minus}\meta{hours}|'|\meta{minutes}|'|.
+% Where the file is not found, the \meta{str var} will be empty.
+% \begin{texnote}
+% The \XeTeX{} engine provides no way to implement this function.
+% \end{texnote}
+% \end{function}
+%
% \begin{function}[TF, added = 2014-07-02]{\file_if_exist_input:n}
% \begin{syntax}
% \cs{file_if_exist_input:n} \Arg{file name}
@@ -195,20 +280,30 @@
% \end{syntax}
% Searches for \meta{file name} using the current \TeX{} search
% path and the additional paths controlled by
-% \cs{file_path_include:n}). If found, inserts the \meta{true code} then
+% \cs{file_path_include:n}. If found, inserts the \meta{true code} then
% reads in the file as additional \LaTeX{} source as described for
% \cs{file_input:n}. Note that \cs{file_if_exist_input:n} does not raise
% an error if the file is not found, in contrast to \cs{file_input:n}.
% \end{function}
%
-% \begin{function}[added = 2014-08-22]
-% {\ior_log_streams:, \iow_log_streams:}
+% \begin{function}[added = 2017-07-07]{\file_input_stop:}
% \begin{syntax}
-% \cs{ior_log_streams:}
-% \cs{iow_log_streams:}
+% \cs{file_input_stop:}
% \end{syntax}
-% Writes in the log file a list of the file names associated with each
-% open stream: intended for tracking down problems.
+% Ends the reading of a file started by \cs{file_input:n} or similar before
+% the end of the file is reached. Where the file reading is being terminated
+% due to an error, \cs{msg_critical:nn(nn)} should be preferred.
+% \begin{texnote}
+% This function must be used on a line on its own: \TeX{} reads files
+% line-by-line and so any additional tokens in the \enquote{current} line
+% will still be read.
+%
+% This is also true if the function is hidden inside another function
+% (which will be the normal case), i.e., all tokens on the same line
+% in the source file are still processed. Putting it on a line by itself
+% in the definition doesn't help as it is the line where it is used that
+% counts!
+% \end{texnote}
% \end{function}
%
% \section{Additions to \pkg{l3int}}
@@ -283,7 +378,7 @@
% \begin{verbatim}
% \prop_map_tokens:Nn \l_my_prop { \str_if_eq:nnT { mykey } }
% \end{verbatim}
-% will expand to the value corresponding to \texttt{mykey}: for each
+% expands to the value corresponding to \texttt{mykey}: for each
% pair in |\l_my_prop| the function \cs{str_if_eq:nnT} receives
% \texttt{mykey}, the \meta{key} and the \meta{value} as its three
% arguments. For that specific task, \cs{prop_item:Nn} is faster.
@@ -301,7 +396,7 @@
% \begin{texnote}
% The result is returned within the \tn{unexpanded}
% primitive (\cs{exp_not:n}), which means that the \meta{value}
-% will not expand further when appearing in an \texttt{x}-type
+% does not expand further when appearing in an \texttt{x}-type
% argument expansion.
% \end{texnote}
% \end{function}
@@ -318,9 +413,9 @@
% \end{syntax}
% Applies \meta{function} to every pair of items
% \meta{seq_1-item}--\meta{seq_2-item} from the two sequences, returning
-% items from both sequences from left to right. The \meta{function} will
-% receive two \texttt{n}-type arguments for each iteration. The mapping
-% will terminate when
+% items from both sequences from left to right. The \meta{function}
+% receives two \texttt{n}-type arguments for each iteration. The mapping
+% terminates when
% the end of either sequence is reached (\emph{i.e.}~whichever sequence has
% fewer items determines how many iterations
% occur).
@@ -331,13 +426,13 @@
% \cs{seq_set_filter:NNn} \meta{sequence_1} \meta{sequence_2} \Arg{inline boolexpr}
% \end{syntax}
% Evaluates the \meta{inline boolexpr} for every \meta{item} stored
-% within the \meta{sequence_2}. The \meta{inline boolexpr} will
-% receive the \meta{item} as |#1|. The sequence of all \meta{items}
+% within the \meta{sequence_2}. The \meta{inline boolexpr}
+% receives the \meta{item} as |#1|. The sequence of all \meta{items}
% for which the \meta{inline boolexpr} evaluated to \texttt{true}
% is assigned to \meta{sequence_1}.
% \begin{texnote}
% Contrarily to other mapping functions, \cs{seq_map_break:} cannot
-% be used in this function, and will lead to low-level \TeX{} errors.
+% be used in this function, and would lead to low-level \TeX{} errors.
% \end{texnote}
% \end{function}
%
@@ -355,7 +450,7 @@
% in \meta{inline function} should be expandable.
% \begin{texnote}
% Contrarily to other mapping functions, \cs{seq_map_break:} cannot
-% be used in this function, and will lead to low-level \TeX{} errors.
+% be used in this function, and would lead to low-level \TeX{} errors.
% \end{texnote}
% \end{function}
%
@@ -369,7 +464,7 @@
% \begin{texnote}
% The result is returned within the \tn{unexpanded}
% primitive (\cs{exp_not:n}), which means that the \meta{item}
-% will not expand further when appearing in an \texttt{x}-type
+% does not expand further when appearing in an \texttt{x}-type
% argument expansion.
% \end{texnote}
% \end{function}
@@ -438,8 +533,8 @@
% \cs{sys_if_shell_p:}
% \cs{sys_if_shell:TF} \Arg{true code} \Arg{false code}
% \end{syntax}
-% Performs a check for whether shell escape is enabled. This will
-% return true if either of restricted or unrestircted shell escape
+% Performs a check for whether shell escape is enabled. This
+% returns true if either of restricted or unrestricted shell escape
% is enabled.
% \end{function}
%
@@ -458,7 +553,7 @@
% \cs{sys_if_shell_restricted:TF} \Arg{true code} \Arg{false code}
% \end{syntax}
% Performs a check for whether \emph{restricted} shell escape is
-% enabled. This will return false if unrestricted shell escape is
+% enabled. This returns false if unrestricted shell escape is
% enabled. Unrestricted shell escape is not considered a superset
% of restricted shell escape in this case. To find whether any
% shell escape is enabled use \cs{sys_if_shell:}.
@@ -495,8 +590,8 @@
% \cs{tl_reverse_tokens:n} \Arg{tokens}
% \end{syntax}
% This function, which works directly on \TeX{} tokens, reverses
-% the order of the \meta{tokens}: the first will be the last and
-% the last will become first. Spaces are preserved. The reversal
+% the order of the \meta{tokens}: the first becomes the last and
+% the last becomes first. Spaces are preserved. The reversal
% also operates within brace groups, but the braces themselves
% are not exchanged, as this would lead to an unbalanced token
% list. For instance, \cs{tl_reverse_tokens:n} |{a~{b()}}|
@@ -505,7 +600,7 @@
% \begin{texnote}
% The result is returned within the \tn{unexpanded}
% primitive (\cs{exp_not:n}), which means that the token
-% list will not expand further when appearing in an \texttt{x}-type
+% list does not expand further when appearing in an \texttt{x}-type
% argument expansion.
% \end{texnote}
% \end{function}
@@ -534,7 +629,7 @@
% These functions are intended to be applied to input which may be
% regarded broadly as \enquote{text}. They traverse the \meta{tokens} and
% change the case of characters as discussed below. The character code of
-% the characters replaced may be arbitrary: the replacement characters will
+% the characters replaced may be arbitrary: the replacement characters
% have standard document-level category codes ($11$ for letters, $12$ for
% letter-like characters which can also be case-changed). Begin-group and
% end-group characters in the \meta{tokens} are normalized and become |{|
@@ -547,16 +642,16 @@
% \end{function}
%
% The functions perform expansion on the input in most cases. In particular,
-% input in the form of token lists or expandable functions will be expanded
+% input in the form of token lists or expandable functions is expanded
% \emph{unless} it falls within one of the special handling classes described
% below. This expansion approach means that in general the result of case
-% changing will match the \enquote{natural} outcome expected from a
+% changing matches the \enquote{natural} outcome expected from a
% \enquote{functional} approach to case modification. For example
% \begin{verbatim}
% \tl_set:Nn \l_tmpa_tl { hello }
% \tl_upper_case:n { \l_tmpa_tl \c_space_tl world }
% \end{verbatim}
-% will produce
+% produces
% \begin{verbatim}
% HELLO WORLD
% \end{verbatim}
@@ -566,11 +661,11 @@
% from the \pkg{etoolbox} package.
%
% \begin{variable}{\l_tl_case_change_math_tl}
-% Case changing will not take place within math mode material so for example
+% Case changing does not take place within math mode material so for example
% \begin{verbatim}
% \tl_upper_case:n { Some~text~$y = mx + c$~with~{Braces} }
% \end{verbatim}
-% will become
+% becomes
% \begin{verbatim}
% SOME TEXT $y = mx + c$ WITH {BRACES}
% \end{verbatim}
@@ -682,7 +777,7 @@
% 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
+% discussed below. Context detection expands input but treats any
% unexpandable control sequences as \enquote{failures} to match a context.
%
% Language-sensitive conversions are enabled using the \meta{language}
@@ -755,7 +850,7 @@
% \begin{texnote}
% The result is returned within the \tn{unexpanded}
% primitive (\cs{exp_not:n}), which means that the \meta{item}
-% will not expand further when appearing in an \texttt{x}-type
+% does not expand further when appearing in an \texttt{x}-type
% argument expansion.
% \end{texnote}
% \end{function}
@@ -778,7 +873,7 @@
% \iow_term:x { \tl_range:nnn { abcdef } { -2 } { -1 } }
% \iow_term:x { \tl_range:nnn { abcdef } { 0 } { -1 } }
% \end{verbatim}
-% will print \texttt{{b}{c}{d}{e}}, \texttt{{c}{d}{e}{f}}, \texttt{{e}{f}}, and an empty
+% prints \texttt{{b}{c}{d}{e}}, \texttt{{c}{d}{e}{f}}, \texttt{{e}{f}}, and an empty
% line to the terminal. The \meta{start index} must always be smaller than
% or equal to the \meta{end index}: if this is not the case then no output
% is generated. Thus
@@ -790,7 +885,7 @@
% \begin{texnote}
% The result is returned within the \tn{unexpanded}
% primitive (\cs{exp_not:n}), which means that the \meta{item}
-% will not expand further when appearing in an \texttt{x}-type
+% does not expand further when appearing in an \texttt{x}-type
% argument expansion.
% \end{texnote}
% \end{function}
@@ -802,7 +897,7 @@
% \cs{peek_N_type:TF} \Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the next \meta{token} in the input stream can be safely
-% grabbed as an \texttt{N}-type argument. The test will be \meta{false}
+% grabbed as an \texttt{N}-type argument. The test is \meta{false}
% if the next \meta{token} is either an explicit or implicit
% begin-group or end-group token (with any character code), or
% an explicit or implicit space character (with character code $32$
@@ -810,9 +905,9 @@
% and \meta{true} in all other cases.
% Note that a \meta{true} result ensures that the next \meta{token} is
% a valid \texttt{N}-type argument. However, if the next \meta{token}
-% is for instance \cs{c_space_token}, the test will take the
+% is for instance \cs{c_space_token}, the test takes the
% \meta{false} branch, even though the next \meta{token} is in fact
-% a valid \texttt{N}-type argument. The \meta{token} will be left
+% a valid \texttt{N}-type argument. The \meta{token} is left
% in the input stream after the \meta{true code} or \meta{false code}
% (as appropriate to the result of the test).
% \end{function}
@@ -827,6 +922,36 @@
%<*initex|package>
% \end{macrocode}
%
+% \subsection{Additions to \pkg{l3basics}}
+%
+% \begin{macro}{\mode_leave_vertical:}
+% The approach here is different to that used by \LaTeXe{} or plain \TeX{},
+% which unbox a void box to force horizontal mode. That inserts the
+% \tn{everypar} tokens \emph{before} the re-inserted unboxing tokens. The
+% approach here uses either the \tn{quitvmode} primitive or the equivalent
+% protected macro. In vertical mode, the \tn{indent} primitive is inserted:
+% this will switch to horizontal mode and insert \tn{everypar} tokens and
+% nothing else. Unlike the \LaTeXe{} version, the availability of \eTeX{}
+% means using a mode test can be done at for example the start of an
+% \tn{halign}. The \tn{quitvmode} primitive essentially wraps the same
+% code up at the engine level.
+% \begin{macrocode}
+\cs_new_protected:Npx \mode_leave_vertical:
+ {
+ \cs_if_exist:NTF \pdftex_quitvmode:D
+ { \pdftex_quitvmode:D }
+ {
+ \exp_not:n
+ {
+ \if_mode_vertical:
+ \exp_after:wN \tex_indent:D
+ \fi:
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \subsection{Additions to \pkg{l3box}}
%
% \begin{macrocode}
@@ -1355,7 +1480,7 @@
\prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop }
{ \@@_scale_pole:Nnnnnn #1 {##1} ##2 }
% \end{macrocode}
-% Negative $x$-scaling values will place the poles in the wrong
+% Negative $x$-scaling values place the poles in the wrong
% location: this is corrected here.
% \begin{macrocode}
\fp_compare:nNnT \l_@@_scale_x_fp < \c_zero_fp
@@ -1463,51 +1588,121 @@
%<@@=file>
% \end{macrocode}
%
+% \begin{macro}
+% {\file_get_mdfive_hash:nN, \file_get_size:nN, \file_get_timestamp:nN}
+% \begin{macro}[aux]{\@@_get_details:nnN}
+% These are all wrappers around the \pdfTeX{} primitives doing the same
+% jobs: as we want consistent file paths to be found, they are all set up
+% using \cs{file_get_full_name:nN} and so are non-expandable \texttt{get}
+% functions. Much of the code is repetitive but we need to branch for
+% \LuaTeX{} (emulation in Lua), for the slightly different syntax
+% needed for \tn{pdftex_mdfivesum:D} and for the fact that primitive
+% coverage varies in other engines.
+% \begin{macrocode}
+\cs_new_protected:Npn \file_get_mdfive_hash:nN #1#2
+ { \@@_get_details:nnN {#1} { mdfivesum } {#2} }
+\cs_new_protected:Npn \file_get_size:nN #1#2
+ { \@@_get_details:nnN {#1} { size } {#2} }
+\cs_new_protected:Npn \file_get_timestamp:nN #1#2
+ { \@@_get_details:nnN {#1} { moddate } {#2} }
+\cs_new_protected:Npn \@@_get_details:nnN #1#2#3
+ {
+ \file_get_full_name:nN {#1} \l_@@_full_name_str
+ \str_set:Nx #3
+ {
+ \use:c { pdftex_file #2 :D } \exp_after:wN
+ { \l_@@_full_name_str }
+ }
+ }
+\cs_if_exist:NTF \luatex_directlua:D
+ {
+ \cs_set_protected:Npn \@@_get_details:nnN #1#2#3
+ {
+ \file_get_full_name:nN {#1} \l_@@_full_name_str
+ \str_set:Nx #3
+ {
+ \lua_now_x:n
+ {
+ l3kernel.file#2
+ ( " \lua_escape_x:n { \l_@@_full_name_str } " )
+ }
+ }
+ }
+ }
+ {
+ \cs_set_protected:Npn \file_get_mdfive_hash:nN #1#2
+ {
+ \file_get_full_name:nN {#1} \l_@@_full_name_str
+ \tl_set:Nx #2
+ {
+ \pdftex_mdfivesum:D file \exp_after:wN
+ { \l_@@_full_name_str }
+ }
+ }
+ \cs_if_exist:NT \xetex_XeTeXversion:D
+ {
+ \cs_set_protected:Npn \@@_get_details:nnN #1#2#3
+ {
+ \tl_clear:N #3
+ \__msg_kernel_error:nnx
+ { kernel } { xetex-primitive-not-available }
+ { \exp_not:c { pdffile #2 } }
+ }
+ }
+ }
+\__msg_kernel_new:nnnn { kernel } { xetex-primitive-not-available }
+ { Primitive~\token_to_str:N #1 not~available }
+ {
+ XeTeX~does~not~currently~provide~functionality~equivalent~to~the~
+ \token_to_str:N #1 primitive.
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}[TF]{\file_if_exist_input:n}
% Input of a file with a test for existence cannot be done the usual
% way as the tokens to insert are in an odd place.
% \begin{macrocode}
\cs_new_protected:Npn \file_if_exist_input:n #1
{
- \file_if_exist:nT {#1}
- { \@@_input:V \l_@@_internal_name_tl }
+ \file_get_full_name:nN {#1} \l__file_full_name_str
+ \str_if_empty:NF \l__file_full_name_str
+ { \@@_input:V \l__file_full_name_str }
}
\cs_new_protected:Npn \file_if_exist_input:nT #1#2
{
- \file_if_exist:nT {#1}
+ \file_get_full_name:nN {#1} \l__file_full_name_str
+ \str_if_empty:NF \l__file_full_name_str
{
#2
- \@@_input:V \l_@@_internal_name_tl
+ \@@_input:V \l__file_full_name_str
}
}
-\cs_new_protected:Npn \file_if_exist_input:nF #1
+\cs_new_protected:Npn \file_if_exist_input:nF #1#2
{
- \file_if_exist:nTF {#1}
- { \@@_input:V \l_@@_internal_name_tl }
+ \file_get_full_name:nN {#1} \l__file_full_name_str
+ \str_if_empty:NTF \l__file_full_name_str
+ {#2}
+ { \@@_input:V \l__file_full_name_str }
}
-\cs_new_protected:Npn \file_if_exist_input:nTF #1#2
+\cs_new_protected:Npn \file_if_exist_input:nTF #1#2#3
{
- \file_if_exist:nTF {#1}
+ \file_get_full_name:nN {#1} \l__file_full_name_str
+ \str_if_empty:NTF \l__file_full_name_str
+ {#3}
{
#2
- \@@_input:V \l_@@_internal_name_tl
+ \@@_input:V \l__file_full_name_str
}
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}{\ior_log_streams:}
-% Redirect output of \cs{ior_list_streams:} to the log.
-% \begin{macrocode}
-\cs_new_protected:Npn \ior_log_streams:
- { \__msg_log_next: \ior_list_streams: }
-% \end{macrocode}
-% \end{macro}
%
-% \begin{macro}{\iow_log_streams:}
-% Redirect output of \cs{iow_list_streams:} to the log.
+% \begin{macro}{\file_input_stop:}
+% A simple rename.
% \begin{macrocode}
-\cs_new_protected:Npn \iow_log_streams:
- { \__msg_log_next: \iow_list_streams: }
+\cs_new_protected:Npn \file_input_stop: { \tex_endinput:D }
% \end{macrocode}
% \end{macro}
%
@@ -1761,10 +1956,10 @@
% usual |{ ? \__prg_break: } { }| to the end of each one. This is
% most conveniently done in two steps using an auxiliary function.
% The mapping then throws away the first tokens of |#2| and |#5|,
-% which for items in the sequences will both be \cs{s_@@}
-% \cs{@@_item:n}. The function to be mapped will then be applied to
+% which for items in both sequences are \cs{s_@@}
+% \cs{@@_item:n}. The function to be mapped are then be applied to
% the two entries. When the code hits the end of one of the
-% sequences, the break material will stop the entire loop and tidy up.
+% sequences, the break material stops the entire loop and tidy up.
% This avoids needing to find the count of the two sequences, or
% worrying about which is longer.
% \begin{macrocode}
@@ -1937,8 +2132,8 @@
% \end{variable}
%
% \begin{macro}[EXP, pTF]{\sys_if_shell:}
-% Performs a check for whether shell escape is enabled. This will
-% return true if either of restricted or unrestricted shell escape
+% Performs a check for whether shell escape is enabled. This
+% returns true if either of restricted or unrestricted shell escape
% is enabled.
% \begin{macrocode}
\prg_new_conditional:Nnn \sys_if_shell: { p , T , F , TF }
@@ -1969,7 +2164,7 @@
%
% \begin{macro}[EXP, pTF]{\sys_if_shell_unrestricted:}
% Performs a check for whether \emph{restricted} shell escape is
-% enabled. This will return false if unrestricted shell escape is
+% enabled. This returns false if unrestricted shell escape is
% enabled. Unrestricted shell escape is not considered a superset
% of restricted shell escape in this case. To find whether any
% shell escape is enabled use \cs{sys_if_shell:}.
@@ -2162,7 +2357,9 @@
\cs_generate_variant:Nn \tl_gset_from_file:Nnn { c }
\cs_new_protected:Npn \@@_set_from_file:NNnn #1#2#3#4
{
- \__file_if_exist:nT {#4}
+ \file_get_full_name:nN {#4} \l__file_full_name_str
+ \str_if_empty:NTF \l__file_full_name_str
+ { \__file_missing:n {#4} }
{
\group_begin:
\exp_args:No \etex_everyeof:D
@@ -2170,7 +2367,7 @@
#3 \scan_stop:
\exp_after:wN \@@_from_file_do:w
\exp_after:wN \prg_do_nothing:
- \tex_input:D \l__file_internal_name_tl \scan_stop:
+ \tex_input:D \l__file_full_name_str \scan_stop:
\exp_args:NNNo \group_end:
#1 #2 \l_@@_internal_a_tl
}
@@ -2204,13 +2401,15 @@
\cs_generate_variant:Nn \tl_gset_from_file_x:Nnn { c }
\cs_new_protected:Npn \@@_set_from_file_x:NNnn #1#2#3#4
{
- \__file_if_exist:nT {#4}
+ \file_get_full_name:nN {#4} \l__file_full_name_str
+ \str_if_empty:NTF \l__file_full_name_str
+ { \__file_missing:n {#4} }
{
\group_begin:
\etex_everyeof:D { \exp_not:N }
#3 \scan_stop:
\tl_set:Nx \l_@@_internal_a_tl
- { \tex_input:D \l__file_internal_name_tl \c_space_token }
+ { \tex_input:D \l__file_full_name_str \c_space_token }
\exp_args:NNNo \group_end:
#1 #2 \l_@@_internal_a_tl
}
@@ -2237,16 +2436,14 @@
% \begin{macro}[EXP]{\tl_lower_case:n, \tl_upper_case:n, \tl_mixed_case:n}
% \begin{macro}[EXP]{\tl_lower_case:nn, \tl_upper_case:nn, \tl_mixed_case:nn}
% The user level functions here are all wrappers around the internal
-% functions for case changing. Note that \cs{tl_mixed_case:nn} could be
-% done without an internal, but this way the logic is slightly clearer as
-% everything essentially follows the same path.
+% functions for case changing.
% \begin{macrocode}
\cs_new:Npn \tl_lower_case:n { \@@_change_case:nnn { lower } { } }
\cs_new:Npn \tl_upper_case:n { \@@_change_case:nnn { upper } { } }
-\cs_new:Npn \tl_mixed_case:n { \@@_mixed_case:nn { } }
+\cs_new:Npn \tl_mixed_case:n { \@@_change_case:nnn { mixed } { } }
\cs_new:Npn \tl_lower_case:nn { \@@_change_case:nnn { lower } }
\cs_new:Npn \tl_upper_case:nn { \@@_change_case:nnn { upper } }
-\cs_new:Npn \tl_mixed_case:nn { \@@_mixed_case:nn }
+\cs_new:Npn \tl_mixed_case:nn { \@@_change_case:nnn { mixed } }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -2264,6 +2461,12 @@
% }
% \begin{macro}[aux, EXP]{\@@_change_case_end:wn}
% \begin{macro}[aux, EXP]{\@@_change_case_group:nwnn}
+% \begin{macro}[aux, EXP]
+% {
+% \@@_change_case_group_lower:nnnn ,
+% \@@_change_case_group_upper:nnnn ,
+% \@@_change_case_group_mixed:nnnn
+% }
% \begin{macro}[aux, EXP]{\@@_change_case_space:wnn}
% \begin{macro}[aux, EXP]{\@@_change_case_N_type:Nwnn}
% \begin{macro}[aux, EXP]{\@@_change_case_N_type:NNNnnn}
@@ -2273,17 +2476,29 @@
% \begin{macro}[aux, EXP]{\@@_change_case_math_group:nwNNnn}
% \begin{macro}[aux, EXP]{\@@_change_case_math_space:wNNnn}
% \begin{macro}[aux, EXP]{\@@_change_case_N_type:Nnnn}
-% \begin{macro}[aux, EXP]{\@@_change_case_char:Nnn}
+% \begin{macro}[aux, EXP]
+% {
+% \@@_change_case_char_lower:Nnn ,
+% \@@_change_case_char_upper:Nnn ,
+% \@@_change_case_char_mixed:Nnn
+% }
% \begin{macro}[aux, EXP]{\@@_change_case_char:nN}
% \begin{macro}[aux, EXP]
% {\@@_change_case_char_auxi:nN, \@@_change_case_char_auxii:nN}
+% \begin{macro}[aux, EXP]
+% {
+% \@@_change_case_char_mixed:N,
+% \@@_change_case_char_lower:N,
+% \@@_change_case_char_upper:N
+% }
% \begin{macro}[aux]
-% {\@@_lookup_lower:N, \@@_lookup_upper:N, \@@_lookup_title:N}
+% {\@@_lookup_mixed:N, \@@_lookup_lower:N, \@@_lookup_upper:N}
% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFviii:nNN}
% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFviii:nNNN}
% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFviii:nNNNN}
% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFviii:nn}
-% \begin{macro}[aux, EXP]{\@@_change_case_cs_letterlike:Nnn}
+% \begin{macro}[aux, EXP]{\@@_change_case_cs_letterlike: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}
@@ -2292,6 +2507,10 @@
% \begin{macro}[aux, EXP]{\@@_change_case_if_expandable:NTF}
% \begin{macro}[aux, EXP]{\@@_change_case_cs_expand:Nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_cs_expand:NN}
+% \begin{macro}[aux, EXP]{\@@_change_case_mixed_skip:N}
+% \begin{macro}[aux, EXP]{\@@_change_case_mixed_skip:NN}
+% \begin{macro}[aux, EXP]{\@@_change_case_mixed_skip_tidy:Nwn}
+% \begin{macro}[aux, EXP]{\@@_change_case_mixed_switch:w}
% The mechanism for the core conversion of case is based on the idea that
% we can use a loop to grab the entire token list plus a quark: the latter is
% used as an end marker and to avoid any brace stripping. Depending on the
@@ -2356,6 +2575,10 @@
% \begin{macrocode}
\cs_new:Npn \@@_change_case_group:nwnn #1#2 \q_recursion_stop #3#4
{
+ \use:c { @@_change_case_group_ #3 : nnnn } {#1} {#2} {#3} {#4}
+ }
+\cs_new:Npn \@@_change_case_group_lower:nnnn #1#2#3#4
+ {
\@@_change_case_output:own
{
\exp_after:wN
@@ -2366,6 +2589,26 @@
}
\@@_change_case_loop:wnn #2 \q_recursion_stop {#3} {#4}
}
+\cs_new_eq:NN \@@_change_case_group_upper:nnnn
+ \@@_change_case_group_lower:nnnn
+% \end{macrocode}
+% For the \enquote{mixed} case, a group is taken as forcing a switch to lower
+% casing. That means we need a separate auxiliary. (Tracking whether we have
+% found a first character inside a group and transferring the information out
+% looks pretty horrible.)
+% \begin{macrocode}
+\cs_new:Npn \@@_change_case_group_mixed:nnnn #1#2#3#4
+ {
+ \@@_change_case_output:own
+ {
+ \exp_after:wN
+ {
+ \exp:w
+ \@@_change_case_aux:nnn {#3} {#4} {#1}
+ }
+ }
+ \@@_change_case_loop:wnn #2 \q_recursion_stop { lower } {#4}
+ }
\exp_last_unbraced:NNo \cs_new:Npn \@@_change_case_space:wnn \c_space_tl
{
\@@_change_case_output:nwn { ~ }
@@ -2397,8 +2640,8 @@
% be either the standard case-changing one or the mixed-case alternative,
% it is not hard-coded into the math loop but is rather passed as argument
% |#3| to \cs{@@_change_case_math:NNNnnn}. If no close-math token is found
-% then the final clean-up will be forced (\emph{i.e.}~there is no assumption
-% of \enquote{well-behaved} code in terms of math mode).
+% then the final clean-up is forced (\emph{i.e.}~there is no assumption
+% of \enquote{well-behaved} input in terms of math mode).
% \begin{macrocode}
\cs_new:Npn \@@_change_case_N_type:NNNnnn #1#2#3
{
@@ -2463,8 +2706,8 @@
\cs_new:Npn \@@_change_case_N_type:Nnnn #1#2#3#4
{
\token_if_cs:NTF #1
- { \@@_change_case_cs_letterlike:Nnn #1 {#3} { } }
- { \@@_change_case_char:Nnn #1 {#3} {#4} }
+ { \@@_change_case_cs_letterlike:Nn #1 {#3} }
+ { \use:c { @@_change_case_char_ #3 :Nnn } #1 {#3} {#4} }
\@@_change_case_loop:wnn #2 \q_recursion_stop {#3} {#4}
}
% \end{macrocode}
@@ -2477,7 +2720,7 @@
% 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
+\cs_new:Npn \@@_change_case_char_lower:Nnn #1#2#3
{
\cs_if_exist_use:cF { @@_change_case_ #2 _ #3 :Nnw }
{ \use_ii:nn }
@@ -2487,6 +2730,24 @@
{ \@@_change_case_char:nN {#2} #1 }
}
}
+\cs_new_eq:NN \@@_change_case_char_upper:Nnn
+ \@@_change_case_char_lower:Nnn
+% \end{macrocode}
+% For mixed case, the code is somewhat different: there is a need to
+% look up both mixed and upper case chars and we have to cover the
+% situation where there is a character to skip over.
+% \begin{macrocode}
+\cs_new:Npn \@@_change_case_char_mixed:Nnn #1#2#3
+ {
+ \@@_change_case_mixed_switch:w
+ \cs_if_exist_use:cF { @@_change_case_mixed_ #3 :Nnw }
+ {
+ \cs_if_exist_use:cF { @@_change_case_upper_ #3 :Nnw }
+ { \use_ii:nn }
+ }
+ #1
+ { \@@_change_case_mixed_skip:N #1 }
+ }
% \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)
@@ -2517,14 +2778,37 @@
{ \@@_change_case_char_auxi:nN {#1} #2 }
}
}
+% \end{macrocode}
+% To allow for the special case of mixed case, we insert here a
+% action-dependent auxiliary.
+% \begin{macrocode}
\cs_new:Npn \@@_change_case_char_auxi:nN #1#2
+ { \use:c { @@_change_case_char_ #1 :N } #2 }
+\cs_new:Npn \@@_change_case_char_lower:N #1
+ {
+ \@@_change_case_output:fwn
+ {
+ \cs_if_exist_use:cF { c__unicode_lower_ \token_to_str:N #1 _tl }
+ { \@@_change_case_char_auxii:nN { lower } #1 }
+ }
+ }
+\cs_new:Npn \@@_change_case_char_upper:N #1
{
\@@_change_case_output:fwn
{
- \cs_if_exist_use:cF { c__unicode_ #1 _ \token_to_str:N #2 _tl }
- { \@@_change_case_char_auxii:nN {#1} #2 }
+ \cs_if_exist_use:cF { c__unicode_upper_ \token_to_str:N #1 _tl }
+ { \@@_change_case_char_auxii:nN { upper } #1 }
}
}
+\cs_new:Npn \@@_change_case_char_mixed:N #1
+ {
+ \cs_if_exist:cTF { c__unicode_mixed_ \token_to_str:N #1 _tl }
+ {
+ \@@_change_case_output:fwn
+ { \tl_use:c { c__unicode_mixed_ \token_to_str:N #1 _tl } }
+ }
+ { \@@_change_case_char_upper:N #1 }
+ }
\cs_if_exist:NTF \utex_char:D
{
\cs_new:Npn \@@_change_case_char_auxii:nN #1#2
@@ -2539,7 +2823,7 @@
}
\cs_new_protected:Npn \@@_lookup_lower:N #1 { \tex_lccode:D `#1 }
\cs_new_protected:Npn \@@_lookup_upper:N #1 { \tex_uccode:D `#1 }
- \cs_new_eq:NN \@@_lookup_title:N \@@_lookup_upper:N
+ \cs_new_eq:NN \@@_lookup_mixed:N \@@_lookup_upper:N
}
{
\cs_new:Npn \@@_change_case_char_auxii:nN #1#2 { \exp_stop_f: #2 }
@@ -2565,10 +2849,19 @@
% 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.
+% letter-like input. The split into two parts here allows us to insert
+% the \enquote{switch} code for mixed casing.
% \begin{macrocode}
-\cs_new:Npn \@@_change_case_cs_letterlike:Nnn #1#2#3
+\cs_new:Npn \@@_change_case_cs_letterlike:Nn #1#2
+ {
+ \str_if_eq:nnTF {#2} { mixed }
+ {
+ \@@_change_case_cs_letterlike:NnN #1 { upper }
+ \@@_change_case_mixed_switch:w
+ }
+ { \@@_change_case_cs_letterlike:NnN #1 {#2} \prg_do_nothing: }
+ }
+\cs_new:Npn \@@_change_case_cs_letterlike:NnN #1#2#3
{
\cs_if_exist:cTF { c_@@_change_case_ #2 _ \token_to_str:N #1 _tl }
{
@@ -2650,10 +2943,10 @@
% When a control sequence is not on the exclude list the other test if
% to see if it is expandable. Once again, if there is a hit then the loop
% function is grabbed as part of the clean-up and reinserted before the
-% now expanded material. The test for expandablity has to check for
+% now expanded material. The test for expandability has to check for
% end-of-recursion as it is needed by the look-ahead code which might hit
% the end of the input. The test is done in two parts as \cs{bool_if:nTF}
-% will choke if |#1| is |(|!
+% would choke if |#1| was |(|!
% \begin{macrocode}
\cs_new:Npn \@@_change_case_if_expandable:NTF #1
{
@@ -2679,6 +2972,51 @@
\cs_new:Npn \@@_change_case_cs_expand:NN #1#2
{ \exp_after:wN #2 #1 }
% \end{macrocode}
+% For mixed case, there is an additional list of exceptions to deal with:
+% once that is sorted, we can move on back to the main loop.
+% \begin{macrocode}
+\cs_new:Npn \@@_change_case_mixed_skip:N #1
+ {
+ \exp_after:wN \@@_change_case_mixed_skip:NN
+ \exp_after:wN #1 \l_tl_mixed_case_ignore_tl
+ \q_recursion_tail \q_recursion_stop
+ }
+\cs_new:Npn \@@_change_case_mixed_skip:NN #1#2
+ {
+ \quark_if_recursion_tail_stop_do:nn {#2}
+ { \@@_change_case_char:nN { mixed } #1 }
+ \int_compare:nNnT { `#1 } = { `#2 }
+ {
+ \use_i_delimit_by_q_recursion_stop:nw
+ {
+ \@@_change_case_output:nwn {#1}
+ \@@_change_case_mixed_skip_tidy:Nwn
+ }
+ }
+ \@@_change_case_mixed_skip:NN #1
+ }
+\cs_new:Npn \@@_change_case_mixed_skip_tidy:Nwn #1#2 \q_recursion_stop #3
+ {
+ \@@_change_case_loop:wnn #2 \q_recursion_stop { mixed }
+ }
+% \end{macrocode}
+% Needed to switch from mixed to lower casing when we have found a
+% first character in the former mode.
+% \begin{macrocode}
+\cs_new:Npn \@@_change_case_mixed_switch:w
+ #1 \@@_change_case_loop:wnn #2 \q_recursion_stop #3
+ {
+ #1
+ \@@_change_case_loop:wnn #2 \q_recursion_stop { lower }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
@@ -3030,10 +3368,10 @@
% \begin{macro}[EXP, aux]{\__unicode_codepoint_to_UTFviii_auxi:n}
% \begin{macro}[EXP, aux]{\__unicode_codepoint_to_UTFviii_auxii:Nnn}
% \begin{macro}[EXP, aux]{\__unicode_codepoint_to_UTFviii_auxiii:n}
-% This code will convert a codepoint into the correct UTF-8 representation.
+% This code converts a codepoint into the correct UTF-8 representation.
% 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
+% this code covers 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 algorithm itself, see
@@ -3338,7 +3676,7 @@
\group_end:
}
\@@_tmp:w { 00DF } { SS } { upper }
- \@@_tmp:w { 00DF } { Ss } { title }
+ \@@_tmp:w { 00DF } { Ss } { mixed }
\@@_tmp:w { 0131 } { I } { upper }
}
\group_end:
@@ -3382,188 +3720,6 @@
% \end{macrocode}
% \end{variable}
%
-% \begin{macro}[aux, EXP]{\@@_mixed_case:nn}
-% \begin{macro}[aux, EXP]{\@@_mixed_case_aux:nn}
-% \begin{macro}[aux, EXP]{\@@_mixed_case_loop:wn}
-% \begin{macro}[aux, EXP]{\@@_mixed_case_group:nwn}
-% \begin{macro}[aux, EXP]{\@@_mixed_case_space:wn}
-% \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}
-% \begin{macro}[aux, EXP]{\@@_mixed_case_skip_tidy:Nwn}
-% \begin{macro}[aux, EXP]{\@@_mixed_case_char:nN}
-% Mixed (title) casing requires some custom handling of the case changing
-% of the first letter in the input followed by a switch to the normal
-% lower casing routine. That could be covered by passing a set of functions
-% to generic routines, but at the cost of making the process rather opaque.
-% Instead, the approach taken here is to use a dedicated set of functions
-% which keep the different loop requirements clearly separate.
-%
-% The main loop looks for the first \enquote{real} char in the input
-% (skipping any pre-letter chars). Once one is found, it is case changed to
-% upper case but first checking that there is not an entry in the exceptions
-% list. Note that simply grabbing the first token in the input is no good
-% here: it can't handle pre-letter tokens or any special treatment of the
-% first letter found (\emph{e.g.}~words starting with \texttt{i} in
-% Turkish). Spaces at the start of the input are passed through without
-% counting as being the \enquote{start} of the first word, while a brace
-% group is assumed to be contain the first char with everything after the
-% brace therefore lower cased.
-% \begin{macrocode}
-\cs_new:Npn \@@_mixed_case:nn #1#2
- {
- \etex_unexpanded:D \exp_after:wN
- {
- \exp:w
- \@@_mixed_case_aux:nn {#1} {#2}
- }
- }
-\cs_new:Npn \@@_mixed_case_aux:nn #1#2
- {
- \group_align_safe_begin:
- \@@_mixed_case_loop:wn
- #2 \q_recursion_tail \q_recursion_stop {#1}
- \@@_change_case_result:n { }
- }
-\cs_new:Npn \@@_mixed_case_loop:wn #1 \q_recursion_stop
- {
- \tl_if_head_is_N_type:nTF {#1}
- { \@@_mixed_case_N_type:Nwn }
- {
- \tl_if_head_is_group:nTF {#1}
- { \@@_mixed_case_group:nwn }
- { \@@_mixed_case_space:wn }
- }
- #1 \q_recursion_stop
- }
-\cs_new:Npn \@@_mixed_case_group:nwn #1#2 \q_recursion_stop #3
- {
- \@@_change_case_output:own
- {
- \exp_after:wN
- {
- \exp:w
- \@@_mixed_case_aux:nn {#3} {#1}
- }
- }
- \@@_change_case_loop:wnn #2 \q_recursion_stop { lower } {#3}
- }
-\exp_last_unbraced:NNo \cs_new:Npn \@@_mixed_case_space:wn \c_space_tl
- {
- \@@_change_case_output:nwn { ~ }
- \@@_mixed_case_loop:wn
- }
-\cs_new:Npn \@@_mixed_case_N_type:Nwn #1#2 \q_recursion_stop
- {
- \quark_if_recursion_tail_stop_do:Nn #1
- { \@@_change_case_end:wn }
- \exp_after:wN \@@_mixed_case_N_type:NNNnn
- \exp_after:wN #1 \l_tl_case_change_math_tl
- \q_recursion_tail ? \q_recursion_stop {#2}
- }
-\cs_new:Npn \@@_mixed_case_N_type:NNNnn #1#2#3
- {
- \quark_if_recursion_tail_stop_do:Nn #2
- { \@@_mixed_case_N_type:Nnn #1 }
- \token_if_eq_meaning:NNTF #1 #2
- {
- \use_i_delimit_by_q_recursion_stop:nw
- {
- \@@_change_case_math:NNNnnn
- #1 #3 \@@_mixed_case_loop:wn
- }
- }
- { \@@_mixed_case_N_type:NNNnn #1 }
- }
-% \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
- {
- \@@_change_case_cs_letterlike:Nnn #1 { upper }
- { \@@_mixed_case_letterlike:Nw }
- \@@_mixed_case_loop:wn #2 \q_recursion_stop {#3}
- }
- {
- \@@_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
-% tokens to skip over too.
-% \begin{macrocode}
-\cs_new:Npn \@@_mixed_case_char:Nn #1#2
- {
- \cs_if_exist_use:cF { @@_change_case_mixed_ #2 :Nnw }
- {
- \cs_if_exist_use:cF { @@_change_case_upper_ #2 :Nnw }
- { \use_ii:nn }
- }
- #1
- { \@@_mixed_case_skip:N #1 }
- }
-\cs_new:Npn \@@_mixed_case_skip:N #1
- {
- \exp_after:wN \@@_mixed_case_skip:NN
- \exp_after:wN #1 \l_tl_mixed_case_ignore_tl
- \q_recursion_tail \q_recursion_stop
- }
-\cs_new:Npn \@@_mixed_case_skip:NN #1#2
- {
- \quark_if_recursion_tail_stop_do:nn {#2}
- { \@@_mixed_case_char:N #1 }
- \int_compare:nNnT { `#1 } = { `#2 }
- {
- \use_i_delimit_by_q_recursion_stop:nw
- {
- \@@_change_case_output:nwn {#1}
- \@@_mixed_case_skip_tidy:Nwn
- }
- }
- \@@_mixed_case_skip:NN #1
- }
-\cs_new:Npn \@@_mixed_case_skip_tidy:Nwn #1#2 \q_recursion_stop #3
- {
- \@@_mixed_case_loop:wn #2 \q_recursion_stop
- }
-\cs_new:Npn \@@_mixed_case_char:N #1
- {
- \cs_if_exist:cTF { c__unicode_title_ #1 _tl }
- {
- \@@_change_case_output:fwn
- { \tl_use:c { c__unicode_title_ #1 _tl } }
- }
- { \@@_change_case_char:nN { upper } #1 }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
% \begin{macro}[aux, EXP]{\@@_change_case_mixed_nl:Nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_mixed_nl:Nw}
% \begin{macro}[aux, EXP]{\@@_change_case_mixed_nl:NNw}