diff options
author | Karl Berry <karl@freefriends.org> | 2017-07-15 21:27:01 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2017-07-15 21:27:01 +0000 |
commit | b1ce47fe4d0e1f06d1b019c3c6eb5f1b0ecd5e14 (patch) | |
tree | 58362abe4b603bb5f6db898b9b835bc8af730b3e /Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx | |
parent | 03b8dcfa3435f0265dfad4fd09aaab8f4ff9c617 (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.dtx | 726 |
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} |