% % -*- coding: utf-8 -*- % % Package interchar: managing character class schemes of XeTeX % % Copyright (C) 2015 Zou Hu % % % % Please report bugs, problems, and suggestions via % % https://github.com/zohooo/interchar % % % % This file may be distributed and/or modified under the conditions % % of the LaTeX Project Public License, either version 1.3 of this % % license or (at your option) any later version. The latest version % % of this license is in % % http://www.latex-project.org/lppl.txt \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{interchar}[2015/02/17 v0.2 managing character class schemes of XeTeX] \RequirePackage{expl3}[2014/05/20] \RequirePackage{xparse} \ExplSyntaxOn % Some more scratch variables. \tl_new:N \l__interchar_a_tl \tl_new:N \l__interchar_b_tl \tl_new:N \l__interchar_x_tl \tl_new:N \l__interchar_y_tl \tl_new:N \l__interchar_ab_tl \tl_new:N \l__interchar_xy_tl % Generate variants for some functions. \cs_generate_variant:Nn \clist_concat:NNN { c } \cs_generate_variant:Nn \int_to_hexadecimal:n { V } \cs_generate_variant:Nn \prop_get:NnN { cx } \cs_generate_variant:Nn \prop_item:cn { cx } \cs_generate_variant:Nn \prop_put:Nnn { cx } \cs_generate_variant:Nn \tl_if_eq:nnT { Vo } % Rename some primitive commands of XeTeX. \cs_new_eq:NN \xetex_intercharstate:D \XeTeXinterchartokenstate \cs_new_eq:NN \xetex_newcharclass:D \newXeTeXintercharclass \cs_new_eq:NN \xetex_charclass:D \XeTeXcharclass \cs_new_eq:NN \xetex_interchartoks:D \XeTeXinterchartoks % Need to update them according to `unicode-letters.tex'. \clist_new:N \g_interchar_default_classes_clist \clist_gset:Nn \g_interchar_default_classes_clist { 1, 2, 3, 256 } \int_new:N \g_interchar_default_newclass_int \int_gset:Nn \g_interchar_default_newclass_int { 4 } \clist_new:c { l_interchar_default_chars_0_clist } \clist_set:cn { l_interchar_default_chars_0_clist } { 1-2319, 231C-2328, 232B-23EF, 23F4-25FF, 2604-2613, 2616-2617, 2619, 2620-2638, 263C-2667, 2669-267E, 2680-26BC, 26C9-26CC, 26CE, 26D2, 26D5-26D7, 26DA-26DB, 26DD-26DE, 26E2-26E9, 26EB-26F0, 26F6, 26FB-26FC, 2705-2707, 270E-2E7F, 2E9A, 2EF4-2EFF, 2FD6-2FEF, 2FFC-3000, 3040-3041, 3043, 3045, 3047, 3049, 3063, 3083, 3085, 3087, 308E, 3095-3098, 30A1, 30A3, 30A5, 30A7, 30A9, 30C3, 30E3, 30E5, 30E7, 30EE, 30F5-30F6, 30FC, 3100-3104, 312E-3130, 318F, 31BB-31BF, 31E4-31FF, 321F, 3248-324F, 32FF, 4DC0-4DFF, A48D-A48F, A4C7-F8FF, FB00-FE0F, FE19-FE2F, FE53, FE67, FE69-FE6A, FE6C-FF00, FF04-FF05, FF66-FF9D, FFA0-FFE1, FFE5-FFFD } \clist_new:c { l_interchar_default_chars_1_clist } \clist_set:cn { l_interchar_default_chars_1_clist } { 231A-231B, 23F0-23F3, 2600-2603, 2614-2615, 2618, 261A-261F, 2639-263B, 2668, 267F, 26BD-26C8, 26CD, 26CF-26D1, 26D3-26D4, 26D8-26D9, 26DC, 26DF-26E1, 26EA, 26F1-26F5, 26F7-26FA, 26FD-2704, 2708-270D, 2E80-2E99, 2E9B-2EF3, 2F00-2FD5, 2FF0-2FFB, 3003-3004, 3006-3007, 3012-3013, 3020-3029, 3030-3034, 3036-303A, 303D-303F, 3042, 3044, 3046, 3048, 304A-3062, 3064-3082, 3084, 3086, 3088-308D, 308F-3094, 309F, 30A2, 30A4, 30A6, 30A8, 30AA-30C2, 30C4-30E2, 30E4, 30E6, 30E8-30ED, 30EF-30F4, 30F7-30FA, 30FF, 3105-312D, 3131-318E, 3190-31BA, 31C0-31E3, 3200-321E, 3220-3247, 3250-32FE, 3300-4DBF, 4E00-A014, A016-A48C, A490-A4C6, F900-FAFF, FE30-FE34, FE45-FE46, FE49-FE4F, FE51, FE58, FE5F-FE66, FE68, FE6B, FF02-FF03, FF06-FF07, FF0A-FF0B, FF0D, FF0F-FF19, FF1C-FF1E, FF20-FF3A, FF3C, FF3E-FF5A, FF5C, FF5E, FFE2-FFE4, 1B000-1B001, 1F000-1F02B, 1F030-1F093, 1F0A0-1F0AE, 1F0B1-1F0BF, 1F0C1-1F0CF, 1F0D1-1F0F5, 1F200-1F202, 1F210-1F23A, 1F240-1F248, 1F250-1F251, 1F300-1F32C, 1F330-1F37D, 1F380-1F39B, 1F39E-1F3B4, 1F3B7-1F3BB, 1F3BD-1F3CE, 1F3D4-1F3F7, 1F400-1F49F, 1F4A1, 1F4A3, 1F4A5-1F4AE, 1F4B0, 1F4B3-1F4FE, 1F507-1F516, 1F525-1F531, 1F54A, 1F550-1F579, 1F57B-1F5A3, 1F5A5-1F5D3, 1F5DC-1F5F3, 1F5FA-1F642, 1F645-1F64F, 1F680-1F6CF, 1F6E0-1F6EC, 1F6F0-1F6F3, } \clist_new:c { l_interchar_default_chars_2_clist } \clist_set:cn { l_interchar_default_chars_2_clist } { 2329, 3008, 300A, 300C, 300E, 3010, 3014, 3016, 3018, 301A, 301D, FE17, FE35, FE37, FE39, FE3B, FE3D, FE3F, FE41, FE43, FE47, FE59, FE5B, FE5D, FF08, FF3B, FF5B, FF5F, FF62 } \clist_new:c { l_interchar_default_chars_3_clist } \clist_set:cn { l_interchar_default_chars_3_clist } { 232A, 3001-3002, 3005, 3009, 300B, 300D, 300F, 3011, 3015, 3017, 3019, 301B-301C, 301E-301F, 303B-303C, 309B-309E, 30A0, 30FB, 30FD-30FE, A015, FE10-FE16, FE18, FE36, FE38, FE3A, FE3C, FE3E, FE40, FE42, FE44, FE48, FE50, FE52, FE54-FE57, FE5A, FE5C, FE5E, FF01, FF09, FF0C, FF0E, FF1A-FF1B, FF1F, FF3D, FF5D, FF60-FF61, FF63-FF65, FF9E-FF9F } \clist_set:cn { l_interchar_default_chars_256_clist } { 302A-302F, 3035, 3099-309A } \prop_new:N \l_interchar_default_toks_prop \prop_put:Nnn \l_interchar_default_toks_prop {0~1} {\xtxHanSpace} \prop_put:Nnn \l_interchar_default_toks_prop {0~2} {\xtxHanSpace} \prop_put:Nnn \l_interchar_default_toks_prop {0~3} {\nobreak\xtxHanSpace} \prop_put:Nnn \l_interchar_default_toks_prop {1~0} {\xtxHanSpace} \prop_put:Nnn \l_interchar_default_toks_prop {2~0} {\nobreak\xtxHanSpace} \prop_put:Nnn \l_interchar_default_toks_prop {3~0} {\xtxHanSpace} \prop_put:Nnn \l_interchar_default_toks_prop {1~1} {\xtxHanGlue} \prop_put:Nnn \l_interchar_default_toks_prop {1~2} {\xtxHanGlue} \prop_put:Nnn \l_interchar_default_toks_prop {1~3} {\nobreak\xtxHanGlue} \prop_put:Nnn \l_interchar_default_toks_prop {2~1} {\nobreak\xtxHanGlue} \prop_put:Nnn \l_interchar_default_toks_prop {2~2} {\nobreak\xtxHanGlue} \prop_put:Nnn \l_interchar_default_toks_prop {2~3} {\xtxHanGlue} \prop_put:Nnn \l_interchar_default_toks_prop {3~1} {\xtxHanGlue} \prop_put:Nnn \l_interchar_default_toks_prop {3~2} {\xtxHanGlue} \prop_put:Nnn \l_interchar_default_toks_prop {3~3} {\nobreak\xtxHanGlue} % Create a new interchar scheme for each package. \msg_new:nnn { interchar } { Empty-Argument } { The~argument~should~not~be~empty! } \tl_new:N \l_interchar_current_scheme_tl \tl_set:Nn \l_interchar_current_scheme_tl {default} \NewDocumentCommand \newintercharscheme { m } { \tl_if_empty:nT {#1} { \msg_critical:nn { interchar } { Empty-Argument } } \clist_new:c { g_interchar_#1_classes_clist } \clist_gset:cn { g_interchar_#1_classes_clist } { 1, 2, 3 } \int_new:c { g_interchar_#1_newclass_int } \int_gset:cn { g_interchar_#1_newclass_int } { 4 } \clist_new:c { l_interchar_#1_chars_1_clist } \clist_new:c { l_interchar_#1_chars_2_clist } \clist_new:c { l_interchar_#1_chars_3_clist } \prop_new:c { l_interchar_#1_toks_prop } % Used for migrating from XeTeX's primitive commands \interchar@migration { #1 } } % High level |\intercharstate| command. % #1: scheme name; #2: state code. \NewDocumentCommand \intercharstate { O{default} m } { \interchar_state:nn {#1} {#2} } \cs_new_protected_nopar:Npn \interchar_state:nn #1#2 { \__interchar_clear_toks:V \l_interchar_current_scheme_tl \clist_map_inline:Nn \g_interchar_default_classes_clist { \__interchar_apply_class:nn {default} {##1} } \__interchar_apply_class:nn {default} {0} \__interchar_apply_toks:n {default} \int_compare:nTF { #2 > 0 } { \clist_map_inline:cn { g_interchar_#1_classes_clist } { \__interchar_apply_class:nn {#1} {##1} } \__interchar_apply_toks:n {#1} % Use \tl_set:Nx rathar than \tl_set:Nn here \tl_set:Nx \l_interchar_current_scheme_tl {#1} } { \tl_set:Nn \l_interchar_current_scheme_tl {default} } } \cs_generate_variant:Nn \interchar_state:nn { VV } % #1: scheme name; #2: class number. \cs_new_protected_nopar:Npn \__interchar_apply_class:nn #1#2 { \clist_map_inline:cn { l_interchar_#1_chars_ \int_to_arabic:n{#2} _clist } { \__interchar_class_split_range:nNN {##1} \l_tmpa_tl \l_tmpb_tl \int_set:Nn \l_tmpa_int { "\l_tmpa_tl } \int_set:Nn \l_tmpb_int { "\l_tmpb_tl } \int_while_do:nn { \l_tmpa_int <= \l_tmpb_int } { \xetex_charclass:D \l_tmpa_int = #2 \int_incr:N \l_tmpa_int } } } % #1: scheme name. \cs_new_protected_nopar:Npn \__interchar_apply_toks:n #1 { \prop_map_inline:cn { l_interchar_#1_toks_prop } { \xetex_interchartoks:D ##1 = {##2} } } % #1: scheme name. \cs_new_protected_nopar:Npn \__interchar_clear_toks:n #1 { \prop_map_inline:cn { l_interchar_#1_toks_prop } { \xetex_interchartoks:D ##1 = {} } } \cs_generate_variant:Nn \__interchar_clear_toks:n { V } % High level |\getintercharstate| command. % #1: scheme name; #2 result control sequence. \DeclareDocumentCommand \getintercharstate { O{default} m } { \interchar_get_state:nN {#1} {#2} } \cs_new_protected_nopar:Npn \interchar_get_state:nN #1#2 { \tl_set:Nx #2 { \interchar_get_state:n {#1} } } % #1: scheme name. This function is fully expandable. \cs_new_nopar:Npn \interchar_get_state:n #1 { \str_if_eq:VnTF \l_interchar_current_scheme_tl { #1 } { 1 } { 0 } } % High level |\intercharnewclass| command. % #1: scheme name; #2: control sequence for class number. \NewDocumentCommand \newintercharclass { O{default} m} { \interchar_newclass:nn { #1 } { #2 } } \cs_new_protected_nopar:Npn \interchar_newclass:nn #1#2 { \int_set:Nn \l_tmpa_int { \int_use:N \use:c {g_interchar_#1_newclass_int} } \int_new:N #2 \int_set_eq:NN #2 \l_tmpa_int \clist_put_right:co {g_interchar_#1_classes_clist} {\int_use:N \l_tmpa_int} \clist_new:c { l_interchar_#1_chars_ \int_use:N\l_tmpa_int _clist } \int_incr:c { g_interchar_#1_newclass_int } } % High level |\intercharclass| command. % #1: scheme name; #2: char range; #3: class number. \NewDocumentCommand \intercharclass { O{default} m m } { \interchar_class:nnn {#1} {#2} {#3} } \bool_new:N \g__interchar_class_delete_char_bool \cs_new_protected_nopar:Npn \interchar_class:nnn #1#2#3 { \int_compare:nT { #3 > 0 } { \int_set:Nn \l_tmpa_int {#3} \clist_if_in:coF {g_interchar_#1_classes_clist} { \int_use:N \l_tmpa_int } { \clist_put_right:co { g_interchar_#1_classes_clist } { \int_use:N\l_tmpa_int } \clist_new:c { l_interchar_#1_chars_ \int_use:N\l_tmpa_int _clist } } \__interchar_class_insert_char:nnn {#1} {#3} {#2} } \bool_set_false:N \g__interchar_class_delete_char_bool \clist_map_inline:cn {g_interchar_#1_classes_clist} { \int_compare:nT { #3 != ##1 } { \bool_if:NTF \g__interchar_class_delete_char_bool { \clist_map_break: } { \__interchar_class_delete_char:nnn {#1} {##1} {#2} } } } } \cs_generate_variant:Nn \interchar_class:nnn { VVV } % High level |\getintercharclass| command. % #1: scheme name; #2: char code; #3: result control sequence. \DeclareDocumentCommand \getintercharclass { O{default} m m } { \interchar_get_class:nnN {#1} {#2} {#3} } \cs_new_protected_nopar:Npn \interchar_get_class:nnN #1#2#3 { \tl_set:Nx #3 { \interchar_get_class:nn {#1} {#2} } } % #1: scheme name; #2: char code. % This function is fully expandable. \cs_new_nopar:Npn \interchar_get_class:nn #1#2 { \__interchar_get_class_aux:vNnn { g_interchar_#1_classes_clist } \__interchar_class_find_char:nnn {#1} {#2} } \cs_generate_variant:Nn \interchar_get_class:nn { VV } \cs_new_nopar:Npn \__interchar_get_class_aux:nNnn #1#2#3#4 { \__interchar_get_class_loop:Nnnw #2 {#3} {#4} #1 , \q_recursion_tail , \q_recursion_stop } \cs_generate_variant:Nn \__interchar_get_class_aux:nNnn { v } \cs_new_nopar:Npn \__interchar_get_class_loop:Nnnw #1#2#3#4 , { \quark_if_recursion_tail_stop:n {#4} #1 {#2} {#4} {#3} \__interchar_get_class_loop:Nnnw #1 {#2} {#3} } % #1: scheme name; #2: class number; #3: char code. \cs_new_nopar:Npn \__interchar_class_find_char:nnn #1#2#3 { \__interchar_class_find_char_aux:vnn {l_interchar_#1_chars_#2_clist} {#2} {#3} } \cs_new_nopar:Npn \__interchar_class_find_char_aux:nnn #1#2#3 { \__interchar_class_find_char_loop:nnw {#2} {#3} #1 , \q_recursion_tail , \q_recursion_stop } \cs_generate_variant:Nn \__interchar_class_find_char_aux:nnn { v } \cs_new_nopar:Npn \__interchar_class_find_char_loop:nnw #1#2#3 , { \quark_if_recursion_tail_stop:n {#3} \int_case:nn { \__interchar_class_compare_char:nn {#2} {#3} } { { -1 } { \use_none_delimit_by_q_recursion_stop:w } { 0 } { #1 % found the char in class #1, stop two level loops \use_i_delimit_by_q_recursion_stop:nw { \use_none_delimit_by_q_recursion_stop:w } } } \__interchar_class_find_char_loop:nnw {#1} {#2} } % #1: char code; #2 char code or char range in Hex form. % result: -1 if #1 before #2; 1 if #1 after #2; 0 otherwise. \cs_new_nopar:Npn \__interchar_class_compare_char:nn #1#2 { \__interchar_class_compare_char_aux:www #1 - #2 - - \q_stop } \cs_new_nopar:Npn \__interchar_class_compare_char_aux:www #1 - #2 - #3 - { \tl_if_empty:nTF { #3 } { \int_compare:nTF { #1 = "#2 } { 0 } { \int_compare:nTF { #1 < "#2 } { -1 } { 1 } } } { \int_compare:nTF { "#2 <= #1 <= "#3 } { 0 } { \int_compare:nTF { #1 < "#2 } { -1 } { 1 } } } \__interchar_class_compare_char_stop:w } \cs_new_nopar:Npn \__interchar_class_compare_char_stop:w #1 \q_stop {} % #1: scheme name; #2: class number; #3 char range. \cs_new_protected_nopar:Npn \__interchar_class_insert_char:nnn #1#2#3 { % store all char ranges before #3 \clist_clear:N \l_tmpa_clist % store all char ranges after #3 \clist_set_eq:Nc \l_tmpb_clist { l_interchar_#1_chars_ \int_to_arabic:n{#2} _clist } \__interchar_class_split_range:nNN {#3} \l__interchar_a_tl \l__interchar_b_tl \tl_set:Nx \l_tmpa_tl { \int_to_hexadecimal:V \l__interchar_a_tl } \tl_set:Nx \l_tmpb_tl { \int_to_hexadecimal:V \l__interchar_b_tl } % if correct position found \bool_set_false:N \l_tmpa_bool \bool_do_until:Nn \l_tmpa_bool { \tl_if_empty:NTF \l_tmpb_clist { \bool_set_true:N \l_tmpa_bool } { \clist_pop:NN \l_tmpb_clist \l__interchar_xy_tl \exp_args:NV \__interchar_class_split_range:nNN { \l__interchar_xy_tl } \l__interchar_x_tl \l__interchar_y_tl \int_compare:nTF { "\l__interchar_y_tl < "\l_tmpa_tl - 1 } { % left \clist_put_right:NV \l_tmpa_clist \l__interchar_xy_tl } { \int_compare:nTF { "\l__interchar_x_tl > "\l_tmpb_tl + 1} { % right \clist_put_left:NV \l_tmpb_clist \l__interchar_xy_tl \bool_set_true:N \l_tmpa_bool } { % middle \int_compare:nT { "\l__interchar_x_tl < "\l_tmpa_tl } { \tl_set_eq:NN \l_tmpa_tl \l__interchar_x_tl } \int_compare:nT { "\l__interchar_y_tl > "\l_tmpb_tl } { \tl_set_eq:NN \l_tmpb_tl \l__interchar_y_tl } } } } } \tl_if_eq:NNTF \l_tmpa_tl \l_tmpb_tl { \tl_set_eq:NN \l__interchar_ab_tl \l_tmpa_tl } { \tl_set:Nx \l__interchar_ab_tl { \l_tmpa_tl - \l_tmpb_tl } } \clist_put_right:NV \l_tmpa_clist \l__interchar_ab_tl \clist_concat:cNN { l_interchar_#1_chars_ \int_to_arabic:n{#2} _clist } \l_tmpa_clist \l_tmpb_clist } % #1: scheme name; #2: class number; #3: char range. \cs_new_protected_nopar:Npn \__interchar_class_delete_char:nnn #1#2#3 { % store all char ranges before #3 \clist_clear:N \l_tmpa_clist % store all char ranges after #3 \clist_set_eq:Nc \l_tmpb_clist { l_interchar_#1_chars_ \int_to_arabic:n{#2} _clist } \__interchar_class_split_range:nNN {#3} \l__interchar_a_tl \l__interchar_b_tl \tl_set:Nx \l_tmpa_tl { \int_to_hexadecimal:V \l__interchar_a_tl } \tl_set:Nx \l_tmpb_tl { \int_to_hexadecimal:V \l__interchar_b_tl } % if correct position found \bool_set_false:N \l_tmpa_bool \bool_do_until:Nn \l_tmpa_bool { \tl_if_empty:NTF \l_tmpb_clist { \bool_set_true:N \l_tmpa_bool } { \clist_pop:NN \l_tmpb_clist \l__interchar_xy_tl \exp_args:NV \__interchar_class_split_range:nNN { \l__interchar_xy_tl } \l__interchar_x_tl \l__interchar_y_tl \int_compare:nTF { "\l__interchar_y_tl < "\l_tmpa_tl} { % left \clist_put_right:NV \l_tmpa_clist \l__interchar_xy_tl } { \int_compare:nTF { "\l__interchar_x_tl > "\l_tmpb_tl} { % right \clist_put_left:NV \l_tmpb_clist \l__interchar_xy_tl \bool_set_true:N \l_tmpa_bool } { % middle: put [x,a-1] and [b+1,y] into clist \int_compare:nTF { "\l_tmpa_tl - "\l__interchar_x_tl = 1 } { \clist_put_right:NV \l_tmpa_clist \l__interchar_x_tl } { \int_compare:nT { "\l_tmpa_tl - "\l__interchar_x_tl > 1 } { \tl_set:Nx \l__interchar_z_tl { \int_to_hexadecimal:n { "\l_tmpa_tl - 1 } } \clist_put_right:Nx \l_tmpa_clist { \l__interchar_x_tl - \l__interchar_z_tl } } } \int_compare:nTF { "\l__interchar_y_tl - "\l_tmpb_tl = 1 } { \clist_put_right:NV \l_tmpa_clist \l__interchar_y_tl } { \int_compare:nT { "\l__interchar_y_tl - "\l_tmpb_tl > 1 } { \tl_set:Nx \l__interchar_z_tl { \int_to_hexadecimal:n { "\l_tmpb_tl + 1 } } \clist_put_right:Nx \l_tmpa_clist { \l__interchar_z_tl - \l__interchar_y_tl } } } \tl_if_eq:NNT \l_tmpa_tl \l_tmpb_tl { \bool_set_true:N \g__interchar_class_delete_char_bool } } } } } \clist_concat:cNN { l_interchar_#1_chars_ \int_to_arabic:n{#2} _clist } \l_tmpa_clist \l_tmpb_clist } % Split #1 with - and put the results into #2 and #3. \NewDocumentCommand \__interchar_class_split_range:nNN { > { \SplitArgument { 1 } { - } } m m m} { \tl_set:No #2 { \use_i:nn #1} \tl_set:No #3 { \use_ii:nn #1} \exp_args:No \IfNoValueT {#3} { \tl_set_eq:NN #3 #2 } } % High level |\interchartoks| command. % #1: scheme name; #2 and #3: class numbers; #4: tokens. \NewDocumentCommand \interchartoks { O{default} m m +m } { \interchar_toks:nnnn {#1} {#2} {#3} {#4} } \cs_new_protected_nopar:Npn \interchar_toks:nnnn #1#2#3#4 { \int_set:Nn \l_tmpa_int {#2} \int_set:Nn \l_tmpb_int {#3} \prop_put:cxn { l_interchar_#1_toks_prop } { \int_use:N \l_tmpa_int \c_space_tl \int_use:N \l_tmpb_int } { #4 } \tl_if_eq:VoT \l_interchar_current_scheme_tl { #1 } { \xetex_interchartoks:D \l_tmpa_int \l_tmpb_int = { #4 } } } \cs_generate_variant:Nn \interchar_toks:nnnn { VVVV } % #1: scheme name; #2 and #3: class numbers; #4: result control sequence. \DeclareDocumentCommand \getinterchartoks { O{default} m m m } { \interchar_get_toks:nnnN {#1} {#2} {#3} {#4} } \cs_new_protected_nopar:Npn \interchar_get_toks:nnnN #1#2#3#4 { \int_set:Nn \l_tmpa_int {#2} \int_set:Nn \l_tmpb_int {#3} \prop_get:cxN { l_interchar_#1_toks_prop } { \int_use:N \l_tmpa_int \c_space_tl \int_use:N \l_tmpb_int } #4 \quark_if_no_value:NT #4 { \tl_clear:N #4 } } % #1: scheme name; #2 and #3: class numbers. % This function is fully expandable. % If #2 or #3 is a control sequence generated from `\newintercharclass', % use the following function variants instead. \cs_new_nopar:Npn \interchar_get_toks:nnn #1#2#3 { \prop_item:cn { l_interchar_#1_toks_prop } { #2 ~ #3 } } \cs_generate_variant:Nn \interchar_get_toks:nnn { nVn, nnV, nVV, VVV } \xetex_intercharstate:D = 1 \ExplSyntaxOff % We need to call LaTeX3 functions. \catcode `\_ = 11 \catcode `\: = 11 % From now on, we use `\newcommand' for commands, `\def' for variables. % First we define some variables. \def\interchar@scheme@name@tl{} \def\interchar@c@tl{} \def\interchar@tmpa@int{} \def\interchar@tmpb@int{} \def\interchar@tmpa@tl{} % Switch between getting and setting values. \newif\ifinterchar@get % Used for migrating from XeTeX's primitive commands. \let \NewIntercharScheme = \newintercharscheme % #1: scheme name. \newcommand\interchar@migration[1]{% \expandafter\def\expandafter\interchar@c@tl\expandafter{\tl_upper_case:n #1}% \expandafter\newcommand\csname\interchar@c@tl IntercharState\endcsname{% \def\interchar@scheme@name@tl{#1}% \interchar@state@auxi }% \expandafter\newcommand\csname Get\interchar@c@tl IntercharState\endcsname{% \interchar_get_state:n{#1}% }% \expandafter\newcommand\csname New\interchar@c@tl IntercharClass\endcsname[1]{% \interchar_newclass:nn {#1} {##1}% }% \expandafter\newcommand\csname\interchar@c@tl IntercharClass\endcsname{% \def\interchar@scheme@name@tl{#1}% \interchar@class@auxi }% \expandafter\newcommand\csname Get\interchar@c@tl IntercharClass\endcsname{% \def\interchar@scheme@name@tl{#1}% \interchar@gettrue \interchar@class@auxi }% \expandafter\newcommand\csname\interchar@c@tl IntercharToks\endcsname{% \def\interchar@scheme@name@tl{#1}% \interchar@toks@auxi }% \expandafter\newcommand\csname Get\interchar@c@tl IntercharToks\endcsname{% \def\interchar@scheme@name@tl{#1}% \interchar@gettrue \interchar@toks@auxi }% } % Commands for scanning number or toks arguments. \newcommand\interchar@scan@number[1]{% \afterassignment#1\count255 % } \newcommand\interchar@scan@number@x[1]{% \afterassignment#1\count255=% } \newcommand\interchar@scan@toks[1]{% \afterassignment#1\toks0 % } % Scanning arguments of `\FOOinterchartokenstate' command. \newcommand\interchar@state@auxi{% \interchar@scan@number \interchar@state@auxii } \newcommand\interchar@state@auxii{% \edef\interchar@tmpa@int{\the\count255}% \interchar_state:VV \interchar@scheme@name@tl \interchar@tmpa@int } % Scanning arguments of `\FOOcharclass' command. \newcommand\interchar@class@auxi{% \interchar@scan@number@x \interchar@class@auxii } \newcommand\interchar@class@auxii{% \edef\interchar@tmpa@int{\the\count255}% \ifinterchar@get \interchar@getfalse \interchar_get_class:VV \interchar@scheme@name@tl \interchar@tmpa@int \else \interchar@scan@number \interchar@class@auxiii \fi } \newcommand\interchar@class@auxiii{% \edef\interchar@tmpb@int{\the\count255}% \interchar_class:VVV \interchar@scheme@name@tl \interchar@tmpa@int \interchar@tmpb@int } % Scanning arguments of `\FOOinterchartoks' and `\getFOOinterchartoks' command. \newcommand\interchar@toks@auxi{% \interchar@scan@number@x \interchar@toks@auxii } \newcommand\interchar@toks@auxii{% \edef\interchar@tmpa@int{\the\count255}% \interchar@scan@number@x \interchar@toks@auxiii } \newcommand\interchar@toks@auxiii{% \edef\interchar@tmpb@int{\the\count255}% \ifinterchar@get \interchar@getfalse \interchar_get_toks:VVV \interchar@scheme@name@tl \interchar@tmpa@int \interchar@tmpb@int \else \interchar@scan@toks \interchar@toks@auxiv \fi } \newcommand\interchar@toks@auxiv{% \edef\interchar@tmpa@tl{\the\toks0}% \interchar_toks:VVVV \interchar@scheme@name@tl \interchar@tmpa@int \interchar@tmpb@int \interchar@tmpa@tl } % Recover catcode changes. \catcode `\_ = 8 \catcode `\: = 12