summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty')
-rw-r--r--Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty970
1 files changed, 970 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty
new file mode 100644
index 00000000000..9a69d0da0a6
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty
@@ -0,0 +1,970 @@
+%%
+%% This is file `l3str.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% l3str.dtx (with options: `package')
+%%
+%% EXPERIMENTAL CODE
+%%
+%% Do not distribute this file without also distributing the
+%% source files specified above.
+%%
+%% Do not distribute a modified version of this file.
+%%
+%% File: l3str.dtx Copyright (C) 2011 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
+%% license or (at your option) any later version. The latest version
+%% of this license is in the file
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% This file is part of the "l3experimental bundle" (The Work in LPPL)
+%% and all files in that bundle must be distributed together.
+%%
+%% The released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX3 Project.
+%%
+%% -----------------------------------------------------------------------
+\RequirePackage{expl3}
+\GetIdInfo$Id: l3str.dtx 2895 2011-10-09 15:58:19Z joseph $
+ {L3 Experimental Strings}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\cs_if_exist:NF \cs_if_exist_use:cF
+ {
+ \cs_new:Npn \cs_if_exist_use:cF #1
+ { \cs_if_exist:cTF {#1} { \use:c {#1} } }
+ }
+\cs_if_exist:NF \use_i:nnnnnnnn
+ { \cs_new:Npn \use_i:nnnnnnnn #1#2#3#4#5#6#7#8 {#1} }
+\cs_set:Npn \str_tmp:w #1
+ {
+ \cs_new_protected:cpx { str_#1:Nn } ##1##2
+ { \exp_not:c { tl_#1:Nx } ##1 { \exp_not:N \tl_to_str:n {##2} } }
+ \exp_args:Nc \cs_generate_variant:Nn { str_#1:Nn } { Nx , cn , cx }
+ }
+\str_tmp:w {set}
+\str_tmp:w {gset}
+\str_tmp:w {put_left}
+\str_tmp:w {gput_left}
+\str_tmp:w {put_right}
+\str_tmp:w {gput_right}
+\cs_set_protected_nopar:Npn \str_tmp:w { }
+\tl_new:N \g_str_tmpa_tl
+\tl_new:N \g_str_result_tl
+\int_new:N \l_str_char_int
+\int_new:N \l_str_bytes_int
+\tl_const:Nx \c_backslash_str { \cs_to_str:N \\ }
+\tl_const:Nx \c_lbrace_str { \cs_to_str:N \{ }
+\tl_const:Nx \c_rbrace_str { \cs_to_str:N \} }
+\tl_const:Nx \c_hash_str { \cs_to_str:N \# }
+\tl_const:Nx \c_percent_str { \cs_to_str:N \% }
+\group_begin:
+\char_set_lccode:nn {`\*}{`\ }
+\char_set_lccode:nn {`\A}{`\A}
+\tl_to_lowercase:n {
+ \group_end:
+ \cs_new:Npn \tl_to_other_str:n #1
+ {
+ \exp_after:wN \tl_to_other_str_loop:w \tl_to_str:n {#1} ~ %
+ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ \q_mark \q_stop
+ }
+ \cs_new_nopar:Npn \tl_to_other_str_loop:w
+ #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 ~ #7 ~ #8 ~ #9 \q_stop
+ {
+ \if_meaning:w A #8
+ \tl_to_other_str_end:w
+ \fi:
+ \tl_to_other_str_loop:w
+ #9 #1 * #2 * #3 * #4 * #5 * #6 * #7 * #8 * \q_stop
+ }
+ \cs_new_nopar:Npn \tl_to_other_str_end:w \fi: #1 \q_mark #2 * A #3 \q_stop
+ { \fi: #2 }
+}
+\cs_new_nopar:Npn \tl_to_other_str:N
+ { \exp_args:No \tl_to_other_str:n }
+\cs_new:Npn \str_sanitize_args:Nn #1 #2
+ {
+ \exp_args:Nf #1
+ { \tl_to_other_str:n {#2} }
+ }
+\cs_new:Npn \str_sanitize_args:Nnn #1#2#3
+ {
+ \exp_args:Nff #1
+ { \tl_to_other_str:n {#2} }
+ { \tl_to_other_str:n {#3} }
+ }
+\cs_new_nopar:Npn \str_length:N { \exp_args:No \str_length:n }
+\cs_new:Npn \str_length:n { \str_sanitize_args:Nn \str_length_unsafe:n }
+\cs_new_nopar:Npn \str_length_unsafe:n #1
+ { \str_length_aux:n { \str_length_loop:NNNNNNNNN #1 } }
+\cs_new:Npn \str_length_ignore_spaces:n #1
+ {
+ \str_length_aux:n
+ { \exp_after:wN \str_length_loop:NNNNNNNNN \tl_to_str:n {#1} }
+ }
+\cs_new:Npn \str_length_aux:n #1
+ {
+ \int_eval:n
+ {
+ #1
+ { X \c_eight } { X \c_seven } { X \c_six }
+ { X \c_five } { X \c_four } { X \c_three }
+ { X \c_two } { X \c_one } { X \c_zero }
+ \q_stop
+ }
+ }
+\cs_set:Npn \str_length_loop:NNNNNNNNN #1#2#3#4#5#6#7#8#9
+ {
+ \if_catcode:w X #9
+ \exp_after:wN \use_none_delimit_by_q_stop:w
+ \fi:
+ \c_nine + \str_length_loop:NNNNNNNNN
+ }
+\cs_set_nopar:Npn \str_head:N { \exp_args:No \str_head:n }
+\cs_set:Npn \str_head:n #1
+ {
+ \exp_after:wN \str_head_aux:w
+ \tl_to_str:n {#1}
+ { { } } ~ \q_stop
+ }
+\cs_set_nopar:Npx \str_head_aux:w #1 ~ %
+ { \exp_not:N \use_i_delimit_by_q_stop:nw #1 { ~ } }
+\cs_new:Npn \str_head_ignore_spaces:n #1
+ { \exp_after:wN \use_i_delimit_by_q_stop:nw \tl_to_str:n {#1} { } \q_stop }
+\cs_new_nopar:Npn \str_head_unsafe:n #1
+ { \use_i_delimit_by_q_stop:nw #1 { } \q_stop }
+\cs_new_nopar:Npn \str_tail:N { \exp_args:No \str_tail:n }
+\cs_set:Npn \str_tail:n #1
+ {
+ \exp_after:wN \str_tail_aux:w
+ \reverse_if:N \if_charcode:w
+ \scan_stop: \tl_to_str:n {#1} X X \q_stop
+ }
+\cs_set_nopar:Npn \str_tail_aux:w #1 X #2 \q_stop { \fi: #1 }
+\cs_new:Npn \str_tail_ignore_spaces:n #1
+ {
+ \exp_after:wN \str_tail_aux_ii:w
+ \tl_to_str:n {#1} X { } X \q_stop
+ }
+\cs_new_nopar:Npn \str_tail_unsafe:n #1
+ { \str_tail_aux_ii:w #1 X { } X \q_stop }
+\cs_set_nopar:Npn \str_tail_aux_ii:w #1 #2 X #3 \q_stop { #2 }
+\cs_new:Npn \str_skip_do:nn #1
+ {
+ \int_compare:nNnTF {#1} > \c_seven
+ { \str_skip_aux:nnnnnnnnn }
+ { \str_skip_end:n }
+ {#1}
+ }
+\cs_new:Npn \str_skip_aux:nnnnnnnnn #1#2 #3#4#5#6#7#8#9
+ { \exp_args:Nf \str_skip_do:nn { \int_eval:n { #1 - \c_seven } } {#2} }
+\cs_new:Npn \str_skip_end:n #1
+ {
+ \if_case:w \int_eval:w #1 \int_eval_end:
+ \str_skip_end_ii:nwn { XXXXXXX }
+ \or: \str_skip_end_ii:nwn { XXXXXX }
+ \or: \str_skip_end_ii:nwn { XXXXX }
+ \or: \str_skip_end_ii:nwn { XXXX }
+ \or: \str_skip_end_ii:nwn { XXX }
+ \or: \str_skip_end_ii:nwn { XX }
+ \or: \str_skip_end_ii:nwn { X }
+ \or: \str_skip_end_ii:nwn { }
+ \else: \str_skip_end_ii:nwn { XXXXXXX }
+ \fi:
+ }
+\cs_new:Npn \str_skip_end_ii:nwn #1 #2 \fi: #3
+ { \fi: \use_i:nnnnnnnn {#3} #1 }
+\cs_new:Npn \str_collect_do:nn #1#2
+ { \str_collect_aux:n {#1} { \str_collect_end_iii:nwNNNNNNN {#2} } }
+\cs_new:Npn \str_collect_aux:n #1
+ {
+ \int_compare:nNnTF {#1} > \c_seven
+ { \str_collect_aux:nnNNNNNNN }
+ { \str_collect_end:n }
+ {#1}
+ }
+\cs_new:Npn \str_collect_aux:nnNNNNNNN #1#2 #3#4#5#6#7#8#9
+ {
+ \exp_args:Nf \str_collect_aux:n
+ { \int_eval:n { #1 - \c_seven } }
+ { #2 #3#4#5#6#7#8#9 }
+ }
+\cs_new:Npn \str_collect_end:n #1
+ {
+ \if_case:w \int_eval:w #1 \int_eval_end:
+ \str_collect_end_ii:nwn { {}{}{}{}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{} }
+ \or: \str_collect_end_ii:nwn { {} }
+ \or: \str_collect_end_ii:nwn { }
+ \else: \str_collect_end_ii:nwn { {}{}{}{}{}{}{} }
+ \fi:
+ }
+\cs_new:Npn \str_collect_end_ii:nwn #1 #2 \fi: #3
+ { \fi: #3 \q_stop #1 }
+\cs_new:Npn \str_collect_end_iii:nwNNNNNNN #1 #2 \q_stop #3#4#5#6#7#8#9
+ { #1 {#2#3#4#5#6#7#8#9} }
+\cs_new_nopar:Npn \str_item:Nn { \exp_args:No \str_item:nn }
+\cs_new:Npn \str_item:nn #1#2
+ {
+ \exp_args:Nf \tl_to_str:n
+ { \str_sanitize_args:Nn \str_item_unsafe:nn {#1} {#2} }
+ }
+\cs_new:Npn \str_item_ignore_spaces:nn #1
+ { \exp_args:No \str_item_unsafe:nn { \tl_to_str:n {#1} } }
+\cs_new_nopar:Npn \str_item_unsafe:nn #1#2
+ {
+ \exp_args:Nff \str_item_aux:nn
+ { \int_eval:n {#2} }
+ { \str_length_unsafe:n {#1} }
+ #1
+ \q_stop
+ }
+\cs_new_nopar:Npn \str_item_aux:nn #1#2
+ {
+ \int_compare:nNnTF {#1} < \c_zero
+ {
+ \int_compare:nNnTF {#1} < {-#2}
+ { \use_none_delimit_by_q_stop:w }
+ {
+ \str_skip_do:nn { #1 + #2 }
+ { \use_i_delimit_by_q_stop:nw }
+ }
+ }
+ {
+ \int_compare:nNnTF {#1} < {#2}
+ {
+ \str_skip_do:nn {#1}
+ { \use_i_delimit_by_q_stop:nw }
+ }
+ { \use_none_delimit_by_q_stop:w }
+ }
+ }
+\cs_new_nopar:Npn \str_from_to:Nnn { \exp_args:No \str_from_to:nnn }
+\cs_new:Npn \str_from_to:nnn #1#2#3
+ {
+ \exp_args:Nf \tl_to_str:n
+ { \str_sanitize_args:Nn \str_from_to_unsafe:nnn {#1}{#2}{#3} }
+ }
+\cs_new:Npn \str_from_to_ignore_spaces:nnn #1
+ { \exp_args:No \str_from_to_unsafe:nnn { \tl_to_str:n {#1} } }
+\cs_new:Npn \str_from_to_unsafe:nnn #1#2#3 % <string> <from> <to>
+ {
+ \str_aux_eval_args:Nnnn \str_from_to_aux:nnnw
+ { \str_length_unsafe:n {#1} }
+ {#2}
+ {#3}
+ #1
+ \q_stop
+ }
+\cs_new:Npn \str_from_to_aux:nnnw #1#2#3 % <len> <from> <to>
+ {
+ \exp_args:Nf \str_from_to_aux_ii:nnw
+ { \str_aux_normalize_range:nn {#2} {#1} }
+ { \str_aux_normalize_range:nn {#3} {#1} }
+ }
+\cs_new:Npn \str_from_to_aux_ii:nnw #1#2
+ {
+ \str_skip_do:nn {#1}
+ {
+ \exp_args:Nf \str_collect_do:nn
+ { \int_eval:n { #2 - #1 } }
+ { \use_i_delimit_by_q_stop:nw }
+ }
+ }
+\cs_new:Npn \str_aux_eval_args:Nnnn #1#2#3#4
+ {
+ \exp_after:wN #1
+ \exp_after:wN { \int_value:w \int_eval:w #2 \exp_after:wN }
+ \exp_after:wN { \int_value:w \int_eval:w #3 \exp_after:wN }
+ \exp_after:wN { \int_value:w \int_eval:w #4 }
+ }
+\cs_new:Npn \str_aux_normalize_range:nn #1#2
+ {
+ \int_eval:n
+ {
+ \if_num:w #1 < \c_zero
+ \if_num:w #1 < - #2 \exp_stop_f:
+ \c_zero
+ \else:
+ #1 + #2
+ \fi:
+ \else:
+ \if_num:w #1 < #2 \exp_stop_f:
+ #1
+ \else:
+ #2
+ \fi:
+ \fi:
+ }
+ }
+\cs_new_nopar:Npn \str_map_tokens:Nn
+ { \exp_args:No \str_map_tokens:nn }
+\cs_new_nopar:Npn \str_map_tokens:nn
+ { \str_sanitize_args:Nn \str_map_tokens_aux:nn }
+\cs_new:Npn \str_map_tokens_aux:nn #1#2
+ {
+ \str_map_tokens_loop:nN {#2} #1
+ { ? \use_none_delimit_by_q_recursion_stop:w } \q_recursion_stop
+ }
+\cs_new_nopar:Npn \str_map_tokens_loop:nN #1#2
+ {
+ \use_none:n #2
+ #1 #2
+ \str_map_tokens_loop:nN {#1}
+ }
+\cs_new_eq:NN \str_map_break_do:n \use_i_delimit_by_q_recursion_stop:nw
+\prg_new_conditional:Npnn \str_if_eq:NN #1#2 { p , TF , T , F }
+ {
+ \if_int_compare:w \pdftex_strcmp:D { \tl_to_str:N #1 } { \tl_to_str:N #2 }
+ = \c_zero \prg_return_true: \else: \prg_return_false: \fi:
+ }
+\prg_new_conditional:Npnn \str_if_contains_char:NN #1#2 { p , T , F , TF }
+ {
+ \str_map_tokens:Nn #1 { \str_if_contains_char_aux:NN #2 }
+ \prg_return_false:
+ }
+\prg_new_conditional:Npnn \str_if_contains_char:nN #1#2 { p , T , F , TF }
+ {
+ \str_map_tokens:nn {#1} { \str_if_contains_char_aux:NN #2 }
+ \prg_return_false:
+ }
+\cs_new_nopar:Npn \str_if_contains_char_aux:NN #1#2
+ {
+ \if_num:w `#1 = `#2 \exp_stop_f:
+ \str_if_contains_char_end:w
+ \fi:
+ }
+\cs_new_nopar:Npn \str_if_contains_char_end:w \fi: #1 \prg_return_false:
+ { \fi: \prg_return_true: }
+\prg_new_conditional:Npnn \str_if_bytes:N #1 { p , T , F , TF }
+ {
+ \str_map_tokens:Nn #1 { \str_if_bytes_aux:N }
+ \prg_return_true:
+ }
+\cs_new_nopar:Npn \str_if_bytes_aux:N #1
+ {
+ \int_compare:nNnF {`#1} < \c_two_hundred_fifty_six
+ {
+ \use_i_delimit_by_q_recursion_stop:nw
+ { \prg_return_false: \use_none:n }
+ }
+ }
+\prg_new_protected_conditional:Npnn \str_aux_hexadecimal_test:N #1 { TF }
+ {
+ \tl_if_in:onTF { \tl_to_str:n {abcdef} } {#1}
+ {
+ \int_set:Nn \l_str_char_int
+ { \c_sixteen * \l_str_char_int + `#1 - 87 }
+ \prg_return_true:
+ }
+ {
+ \if_num:w \c_fifteen < "1 \exp_not:N #1 \exp_stop_f:
+ \int_set:Nn \l_str_char_int
+ { \c_sixteen * \l_str_char_int + "#1 }
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+ }
+\prg_new_protected_conditional:Npnn \str_aux_octal_test:N #1 { TF }
+ {
+ \if_num:w \c_seven < '1 \exp_not:N #1 \exp_stop_f:
+ \int_set:Nn \l_str_char_int
+ { \c_eight * \l_str_char_int + '#1 }
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \str_aux_char_if_octal_digit:NTF #1
+ { \tl_if_in:nnTF { 01234567 } {#1} }
+\cs_new_protected:Npn \str_input:Nn #1#2
+ {
+ \str_aux_escape:NNNn \token_to_str:N \token_to_str:N \token_to_str:N {#2}
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected:Npn \str_ginput:Nn #1#2
+ {
+ \str_aux_escape:NNNn \token_to_str:N \token_to_str:N \token_to_str:N {#2}
+ \tl_gset_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_eq:NN \str_aux_escape_unescaped:N \use:n
+\cs_new_eq:NN \str_aux_escape_escaped:N \use:n
+\cs_new_eq:NN \str_aux_escape_raw:N \use:n
+\cs_new_protected:Npn \str_aux_escape:NNNn #1#2#3#4
+ {
+ \group_begin:
+ \cs_set_nopar:Npn \str_aux_escape_unescaped:N { #1 }
+ \cs_set_nopar:Npn \str_aux_escape_escaped:N { #2 }
+ \cs_set_nopar:Npn \str_aux_escape_raw:N { #3 }
+ \int_set:Nn \tex_escapechar:D {92}
+ \tl_gset:Nx \g_str_result_tl { \tl_to_other_str:n {#4} }
+ \tl_gset:Nx \g_str_result_tl
+ {
+ \exp_after:wN \str_aux_escape_loop:N \g_str_result_tl
+ \q_recursion_tail \q_recursion_stop
+ }
+ \group_end:
+ }
+\cs_new_nopar:Npn \str_aux_escape_loop:N #1
+ {
+ \cs_if_exist_use:cF { str_aux_escape_\token_to_str:N #1:w }
+ { \str_aux_escape_unescaped:N #1 }
+ \str_aux_escape_loop:N
+ }
+\cs_new_nopar:cpn { str_aux_escape_ \c_backslash_str :w }
+ \str_aux_escape_loop:N #1
+ {
+ \cs_if_exist_use:cF { str_aux_escape_/\token_to_str:N #1:w }
+ { \str_aux_escape_escaped:N #1 }
+ \str_aux_escape_loop:N
+ }
+\cs_new_eq:cN
+ { str_aux_escape_ \c_backslash_str q_recursion_tail :w }
+ \use_none_delimit_by_q_recursion_stop:w
+\cs_new_eq:cN
+ { str_aux_escape_ / \c_backslash_str q_recursion_tail :w }
+ \use_none_delimit_by_q_recursion_stop:w
+\cs_new_nopar:cpn { str_aux_escape_~:w } { }
+\cs_new_nopar:cpx { str_aux_escape_/a:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^G }
+\cs_new_nopar:cpx { str_aux_escape_/t:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^I }
+\cs_new_nopar:cpx { str_aux_escape_/n:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^J }
+\cs_new_nopar:cpx { str_aux_escape_/f:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^L }
+\cs_new_nopar:cpx { str_aux_escape_/r:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^M }
+\cs_new_nopar:cpx { str_aux_escape_/e:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^[ }
+\cs_new_nopar:cpn { str_aux_escape_/x:w } \str_aux_escape_loop:N
+ {
+ \if_false: { \fi: }
+ \int_zero:N \l_str_char_int
+ \str_aux_escape_x_test:N
+ }
+\cs_new_protected_nopar:Npx \str_aux_escape_x_test:N #1
+ {
+ \exp_not:N \token_if_eq_charcode:NNTF \c_space_token #1
+ { \exp_not:N \str_aux_escape_x_test:N }
+ {
+ \exp_not:N \token_if_eq_charcode:NNTF \c_lbrace_str #1
+ { \exp_not:N \str_aux_escape_x_braced_loop:N }
+ { \exp_not:N \str_aux_escape_x_unbraced_i:N #1 }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_aux_escape_x_unbraced_i:N #1
+ {
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_aux_escape_x_unbraced_ii:N }
+ { \str_aux_escape_x_end: #1 }
+ }
+\cs_new_protected_nopar:Npn \str_aux_escape_x_unbraced_ii:N #1
+ {
+ \token_if_eq_charcode:NNTF \c_space_token #1
+ { \str_aux_escape_x_unbraced_ii:N }
+ {
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_aux_escape_x_end: }
+ { \str_aux_escape_x_end: #1 }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_aux_escape_x_braced_loop:N #1
+ {
+ \token_if_eq_charcode:NNTF \c_space_token #1
+ { \str_aux_escape_x_braced_loop:N }
+ {
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_aux_escape_x_braced_loop:N }
+ { \str_aux_escape_x_braced_end:N #1 }
+ }
+ }
+\cs_new_protected_nopar:Npx \str_aux_escape_x_braced_end:N #1
+ {
+ \exp_not:N \token_if_eq_charcode:NNTF \c_rbrace_str #1
+ { \exp_not:N \str_aux_escape_x_end: }
+ {
+ \msg_error:nn { str } { x-missing-brace }
+ \exp_not:N \str_aux_escape_x_end: #1
+ }
+ }
+\group_begin:
+ \char_set_catcode_other:N \^^@
+ \cs_new_protected_nopar:Npn \str_aux_escape_x_end:
+ {
+ \group_begin:
+ \char_set_lccode:nn { \c_zero } { \l_str_char_int }
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \tl_gput_right:Nx \g_str_result_tl
+ { \if_false: } \fi:
+ \str_aux_escape_raw:N ^^@
+ \str_aux_escape_loop:N
+ }
+ }
+\group_end:
+\msg_new:nnn { str } { x-missing-brace }
+ {
+ You~wrote~something~like~
+ `\iow_char:N\\x\{ \int_to_hexadecimal:n { \l_str_char_int }'.~
+ The~closing~brace~is~missing.
+ }
+\group_begin:
+ \char_set_catcode_other:n {`\^^@}
+ \cs_new_protected_nopar:Npn \str_aux_convert_store:
+ {
+ \char_set_lccode:nn {\c_zero} {\l_str_char_int}
+ \tl_to_lowercase:n { \tl_gput_right:Nx \g_str_result_tl {^^@} }
+ }
+ \cs_new_protected_nopar:Npn \str_aux_convert_store:NNn #1#2#3
+ {
+ \char_set_lccode:nn {\c_zero} {#3}
+ \tl_to_lowercase:n { #1 #2 {^^@} }
+ }
+\group_end:
+\cs_new_nopar:Npn \str_aux_byte_to_hexadecimal:N #1
+ {
+ \int_compare:nNnTF {`#1} < {256}
+ {
+ \int_to_letter:n { \int_div_truncate:nn {`#1} \c_sixteen }
+ \int_to_letter:n { \int_mod:nn {`#1} \c_sixteen }
+ }
+ { \msg_expandable_error:n { Invalid~byte~`#1'. } }
+ }
+\cs_new_nopar:Npn \str_aux_byte_to_octal:N #1
+ {
+ \int_compare:nNnTF {`#1} < {64}
+ {
+ 0
+ \int_to_letter:n { \int_div_truncate:nn {`#1} \c_eight }
+ \int_to_letter:n { \int_mod:nn {`#1} \c_eight }
+ }
+ {
+ \int_compare:nNnTF {`#1} < {256}
+ { \int_to_octal:n {`#1} }
+ { \msg_expandable_error:n { Invalid~byte~`#1'. } }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_escape_hexadecimal:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_aux_byte_to_hexadecimal:N }
+ }
+\tl_const:Nx \c_str_bytes_escape_name_str
+ { \c_hash_str \c_percent_str \c_lbrace_str \c_rbrace_str () /<>[] }
+\cs_new_protected_nopar:Npn \str_bytes_escape_name:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_bytes_escape_name_aux:N }
+ }
+\cs_new_nopar:Npn \str_bytes_escape_name_aux:N #1
+ {
+ \int_compare:nNnTF {`#1} < {"21}
+ { \c_hash_str \str_aux_byte_to_hexadecimal:N #1 }
+ {
+ \int_compare:nNnTF {`#1} > {"7E}
+ { \c_hash_str \str_aux_byte_to_hexadecimal:N #1 }
+ {
+ \str_if_contains_char:NNTF \c_str_bytes_escape_name_str #1
+ { \c_hash_str \str_aux_byte_to_hexadecimal:N #1 }
+ {#1}
+ }
+ }
+ }
+\tl_const:Nx \c_str_bytes_escape_string_str { \c_backslash_str ( ) }
+\cs_new_protected_nopar:Npn \str_bytes_escape_string:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_bytes_escape_string_aux:N }
+ }
+\cs_new_nopar:Npn \str_bytes_escape_string_aux:N #1
+ {
+ \int_compare:nNnTF {`#1} < {"21}
+ { \c_backslash_str \str_aux_byte_to_octal:N #1 }
+ {
+ \int_compare:nNnTF {`#1} > {"7E}
+ { \c_backslash_str \str_aux_byte_to_octal:N #1 }
+ {
+ \str_if_contains_char:NNT \c_str_bytes_escape_string_str #1
+ { \c_backslash_str }
+ #1
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_hexadecimal:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \int_zero:N \l_str_char_int
+ \exp_last_unbraced:Nf \str_bytes_unescape_hexadecimal_aux:N
+ { \tl_to_other_str:N #2 } 0
+ \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_hexadecimal_aux:N #1
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_bytes_unescape_hexadecimal_aux_ii:N }
+ { \str_bytes_unescape_hexadecimal_aux:N }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_hexadecimal_aux_ii:N #1
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \str_aux_hexadecimal_test:NTF #1
+ {
+ \str_aux_convert_store:
+ \int_zero:N \l_str_char_int
+ \str_bytes_unescape_hexadecimal_aux:N
+ }
+ { \str_bytes_unescape_hexadecimal_aux_ii:N }
+ }
+\group_begin:
+ \char_set_lccode:nn {`\*} {`\#}
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_name:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \int_zero:N \l_str_char_int
+ \exp_last_unbraced:Nf \str_bytes_unescape_name_aux:wN
+ { \tl_to_other_str:N #2 }
+ * \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_name_aux:wN #1 * #2
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \quark_if_recursion_tail_stop:N #2
+ \str_aux_hexadecimal_test:NTF #2
+ { \str_bytes_unescape_name_aux_ii:NN #2 }
+ {
+ \tl_gput_right:Nx \g_str_result_tl { \c_hash_str }
+ \str_bytes_unescape_name_aux:wN #2
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_name_aux_ii:NN #1#2
+ {
+ \str_aux_hexadecimal_test:NTF #2
+ {
+ \str_aux_convert_store:
+ \int_zero:N \l_str_char_int
+ \str_bytes_unescape_name_aux:wN
+ }
+ {
+ \tl_gput_right:Nx \g_str_result_tl { \c_hash_str #1 }
+ \int_zero:N \l_str_char_int
+ \str_bytes_unescape_name_aux:wN #2
+ }
+ }
+\group_begin:
+ \char_set_lccode:nn {`\*} {`\\}
+ \char_set_catcode_other:N \^^J
+ \char_set_catcode_other:N \^^M
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_string:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \exp_last_unbraced:Nf \str_bytes_unescape_string_aux:wN
+ { \tl_to_other_str:N #2 }
+ * \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_string_aux:wN #1 * #2
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \quark_if_recursion_tail_stop:N #2
+ \int_zero:N \l_str_char_int
+ \str_aux_octal_test:NTF #2
+ { \str_bytes_unescape_string_aux_d:N }
+ {
+ \int_set:Nn \l_str_char_int
+ {
+ \prg_case_str:xxn {#2}
+ {
+ {n} {10}
+ {r} {13}
+ {t} {9}
+ {b} {8}
+ {f} {12}
+ {(} {40}
+ {)} {41}
+ {\c_backslash_str} {92}
+ {^^J} {-1}
+ {^^M} {-1}
+ }
+ {`#2}
+ }
+ \int_compare:nNnF \l_str_char_int = \c_minus_one
+ { \str_aux_convert_store: }
+ \str_bytes_unescape_string_aux:wN
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_string_aux_d:N #1
+ {
+ \str_aux_octal_test:NTF #1
+ { \str_bytes_unescape_string_aux_dd:N }
+ {
+ \str_aux_convert_store:
+ \str_bytes_unescape_string_aux:wN #1
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_string_aux_dd:N #1
+ {
+ \str_aux_octal_test:NTF #1
+ {
+ \str_aux_convert_store:
+ \str_bytes_unescape_string_aux:wN
+ }
+ {
+ \str_aux_convert_store:
+ \str_bytes_unescape_string_aux:wN #1
+ }
+ }
+\tl_const:Nx \c_str_bytes_percent_encode_str { \tl_to_str:n { [] } }
+\tl_const:Nx \c_str_bytes_percent_encode_not_str { \tl_to_str:n { "-.<> } }
+\cs_new_protected_nopar:Npn \str_bytes_percent_encode:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_bytes_percent_encode_aux:N }
+ }
+\cs_new_nopar:Npn \str_bytes_percent_encode_aux:N #1
+ {
+ \int_compare:nNnTF {`#1} < {"41}
+ {
+ \str_if_contains_char:NNTF \c_str_bytes_percent_encode_not_str #1
+ { #1 }
+ { \c_percent_str \str_aux_byte_to_hexadecimal:N #1 }
+ }
+ {
+ \int_compare:nNnTF {`#1} > {"7E}
+ { \c_percent_str \str_aux_byte_to_hexadecimal:N #1 }
+ {
+ \str_if_contains_char:NNTF \c_str_bytes_percent_encode_str #1
+ { \c_percent_str \str_aux_byte_to_hexadecimal:N #1 }
+ { #1 }
+ }
+ }
+ }
+\group_begin:
+ \char_set_lccode:nn {`\*} {`\%}
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_protected_nopar:Npn \str_bytes_percent_decode:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \exp_last_unbraced:Nf \str_bytes_percent_decode_aux:wN
+ { \tl_to_other_str:N #2 }
+ * \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+ \cs_new_protected_nopar:Npn \str_bytes_percent_decode_aux:wN #1 * #2
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \quark_if_recursion_tail_stop:N #2
+ \int_zero:N \l_str_char_int
+ \str_aux_hexadecimal_test:NTF #2
+ { \str_bytes_percent_decode_aux_ii:NN #2 }
+ {
+ \tl_gput_right:Nx \g_str_result_tl { \c_percent_str }
+ \str_bytes_percent_decode_aux:wN #2
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_percent_decode_aux_ii:NN #1#2
+ {
+ \str_aux_hexadecimal_test:NTF #2
+ {
+ \str_aux_convert_store:
+ \str_bytes_percent_decode_aux:wN
+ }
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \str_bytes_percent_decode_aux:wN #2
+ }
+ }
+\cs_new_protected_nopar:Npn \str_native_from_UTF_viii:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \exp_last_unbraced:Nf \str_native_from_UTF_viii_aux_i:N
+ { \tl_to_other_str:N #2 }
+ \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected_nopar:Npn \str_native_from_UTF_viii_aux_i:N #1
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \int_set:Nn \l_str_char_int { `#1 }
+ \str_native_from_UTF_viii_aux_ii:nN {128} \c_one
+ \str_native_from_UTF_viii_aux_ii:nN {64} \c_zero
+ \str_native_from_UTF_viii_aux_ii:nN {32} \c_two
+ \str_native_from_UTF_viii_aux_ii:nN {16} \c_three
+ \str_native_from_UTF_viii_aux_ii:nN {8} \c_four
+ \msg_error:nnx { str } { utf8-invalid-byte } {#1}
+ \use_i:nnn \str_native_from_UTF_viii_aux_i:N
+ \q_stop
+ \str_native_from_UTF_viii_aux_iii:N
+ }
+\cs_new_protected_nopar:Npn
+ \str_native_from_UTF_viii_aux_ii:nN #1#2
+ {
+ \int_compare:nNnTF \l_str_char_int < {#1}
+ {
+ \int_set_eq:NN \l_str_bytes_int #2
+ \use_none_delimit_by_q_stop:w
+ }
+ { \int_sub:Nn \l_str_char_int {#1} }
+ }
+\cs_new_protected_nopar:Npn
+ \str_native_from_UTF_viii_aux_iii:N #1
+ {
+ \int_compare:nNnTF \l_str_bytes_int < \c_two
+ { \str_native_from_UTF_viii_aux_iv: #1 }
+ {
+ \if_meaning:w \q_recursion_tail #1
+ \msg_error:nn { str } { utf8-premature-end }
+ \exp_after:wN \use_none_delimit_by_q_recursion_stop:w
+ \fi:
+ \quark_if_recursion_tail_stop:N #1
+ \tex_multiply:D \l_str_char_int by 64 \scan_stop: % no interface??
+ \int_decr:N \l_str_bytes_int
+ \int_compare:nNnTF {`#1} < {128}
+ { \use_ii:nn }
+ { \int_compare:nNnTF {`#1} < {192} }
+ {
+ \int_add:Nn \l_str_char_int { `#1 - 128 }
+ \str_native_from_UTF_viii_aux_iii:N
+ }
+ {
+ \msg_error:nnx { str } { utf8-missing-byte } {#1}
+ \str_native_from_UTF_viii_aux_i:N #1
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn
+ \str_native_from_UTF_viii_aux_iv:
+ {
+ \int_compare:nNnTF \l_str_bytes_int = \c_zero
+ {
+ \msg_error:nnx { str } { utf8-extra-byte }
+ { \int_eval:n { \l_str_char_int + 128 } }
+ }
+ {
+ \pdftex_if_engine:TF
+ {
+ \int_compare:nNnTF { \l_str_char_int } < { 256 }
+ { \str_aux_convert_store: }
+ {
+ \msg_error:nnx { str } { utf8-pdftex-overflow }
+ { \int_use:N \l_str_char_int }
+ }
+ }
+ { \str_aux_convert_store: }
+ }
+ \str_native_from_UTF_viii_aux_i:N
+ }
+\msg_new:nnn { str } { utf8-invalid-byte }
+ {
+ \int_compare:nNnTF {`#1} < {256}
+ { Byte~number~\int_eval:n {`#1}~invalid~in~utf-8~encoding. }
+ { The~character~number~\int_eval:n {`#1}~is~not~a~byte. }
+ }
+\msg_new:nnn { str } { utf8-missing-byte }
+ { The~byte~number~\int_eval:n {`#1}~is~not~a~valid~continuation~byte. }
+\msg_new:nnn { str } { utf8-extra-byte }
+ { The~byte~number~\int_eval:n {`#1}~is~only~valid~as~a~continuation~byte. }
+\msg_new:nnnn { str } { utf8-premature-end }
+ { Incomplete~last~utf8~character. }
+ {
+ The~sequence~of~byte~that~I~need~to~convert~to~utf8 \
+ ended~before~the~last~character~was~complete.~Perhaps \
+ it~was~mistakenly~truncated?
+ }
+\msg_new:nnn { str } { utf8-pdftex-overflow }
+ { The~character~number~#1~is~too~big~for~pdfTeX. }
+\cs_new_protected_nopar:Npn \str_UTF_viii_from_native:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \str_map_tokens:Nn #2 \str_UTF_viii_from_native_aux_i:N
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected_nopar:Npn \str_UTF_viii_from_native_aux_i:N #1
+ {
+ \int_set:Nn \l_str_char_int {`#1}
+ \int_compare:nNnTF \l_str_char_int < {128}
+ { \tl_gput_right:Nx \g_str_result_tl {#1} }
+ {
+ \tl_gclear:N \g_str_tmpa_tl
+ \int_set:Nn \l_str_bytes_int { 64 }
+ \str_UTF_viii_from_native_aux_ii:n {32}
+ \str_UTF_viii_from_native_aux_ii:n {16}
+ \str_UTF_viii_from_native_aux_ii:n {8}
+ \ERROR % somehow the unicode char was > "1FFFFF > "10FFFF
+ \tl_gclear:N \g_str_tmpa_tl
+ \use_none:n \q_stop
+ \int_add:Nn \l_str_char_int { 2 * \l_str_bytes_int }
+ \str_aux_convert_store:
+ \tl_gput_right:Nx \g_str_result_tl { \g_str_tmpa_tl }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_UTF_viii_from_native_aux_ii:n #1
+ {
+ \str_aux_convert_store:NNn
+ \tl_gput_left:Nx \g_str_tmpa_tl
+ { 128 + \int_mod:nn { \l_str_char_int } {64} }
+ \tex_divide:D \l_str_char_int by 64 \scan_stop: % no interface??
+ \int_add:Nn \l_str_bytes_int {#1}
+ \int_compare:nNnT \l_str_char_int < {#1}
+ { \use_none_delimit_by_q_stop:w }
+ }
+\cs_gset:Npn \str_length_skip_spaces:N
+ { \exp_args:No \str_length_skip_spaces:n }
+\cs_gset_eq:NN \str_length_skip_spaces:n \str_length_ignore_spaces:n
+%%
+%%
+%% End of file `l3str.sty'.