summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Master/texmf-dist/doc/latex/unicodefonttable/README.md29
-rw-r--r--Master/texmf-dist/doc/latex/unicodefonttable/TODO.md20
-rw-r--r--Master/texmf-dist/doc/latex/unicodefonttable/changes.txt20
-rw-r--r--Master/texmf-dist/doc/latex/unicodefonttable/l3doc-TUB.cls2306
-rw-r--r--Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-code.pdfbin0 -> 890196 bytes
-rw-r--r--Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-code.tex4
-rw-r--r--Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-doc.pdfbin0 -> 707853 bytes
-rw-r--r--Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-doc.tex6
-rw-r--r--Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-samples.pdfbin0 -> 742559 bytes
-rw-r--r--Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-samples.tex104
-rw-r--r--Master/texmf-dist/source/latex/unicodefonttable/unicodefonttable.dtx2295
-rw-r--r--Master/texmf-dist/source/latex/unicodefonttable/unicodefonttable.ins72
-rw-r--r--Master/texmf-dist/tex/latex/unicodefonttable/unicodefont.tex125
-rw-r--r--Master/texmf-dist/tex/latex/unicodefonttable/unicodefonttable.sty725
-rwxr-xr-xMaster/tlpkg/bin/tlpkg-ctan-check2
-rwxr-xr-xMaster/tlpkg/libexec/ctan2tds1
-rw-r--r--Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc1
-rw-r--r--Master/tlpkg/tlpsrc/unicodefonttable.tlpsrc0
18 files changed, 5709 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/latex/unicodefonttable/README.md b/Master/texmf-dist/doc/latex/unicodefonttable/README.md
new file mode 100644
index 00000000000..b1f92c1fd0c
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/unicodefonttable/README.md
@@ -0,0 +1,29 @@
+# The unicodefonttable package
+
+-----
+
+This package produces font tables for unicode fonts as well as for
+8bit fonts. The table layout can be adjusted in various ways
+including restricting the range of output to show only a portion of a
+specific font.
+
+To quickly produce a one-off table there is a stand-alone version
+`unicodefont.tex` that asks you a few questions and then generates the
+table --- somewhat similar to `nfssfont.tex` for 8-bit fonts.
+
+
+The official package source can be found at:
+
+ https://github.com/FrankMittelbach/fmitex-unicodefonttable/
+
+The license is LPPL.
+
+For version information see the .dtx file.
+
+-----
+
+Copyright (C) Frank Mittelbach (for copyright date see the .dtx file)<br />
+<https://latex-project.org/> <br />
+All rights reserved.
+
+
diff --git a/Master/texmf-dist/doc/latex/unicodefonttable/TODO.md b/Master/texmf-dist/doc/latex/unicodefonttable/TODO.md
new file mode 100644
index 00000000000..6cee8ebf495
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/unicodefonttable/TODO.md
@@ -0,0 +1,20 @@
+# Collection of possible todos
+
+These are an unsorted collection of thoughts by others or myself and may or may not get done depending ...
+
+
+## Comparing
+
+- When comparing, I suggest writing the log file with the
+ the list of glyphs found only in the comparison font. That way, people
+ developing a font who want to have equal coverage can easily see what
+ glyphs they are missing. Since you are already discovering the
+ information, why not log it ...
+
+
+- Also, if there are first-font-only symbols (maybe not in
+ this case -- is there a way to get a textual list of the differing code
+ points?), I'd suggest trying an open box (cf. the shaded box for
+ second-font-only).
+
+
diff --git a/Master/texmf-dist/doc/latex/unicodefonttable/changes.txt b/Master/texmf-dist/doc/latex/unicodefonttable/changes.txt
new file mode 100644
index 00000000000..a632e273f8a
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/unicodefonttable/changes.txt
@@ -0,0 +1,20 @@
+2021-10-19 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * unicodefonttable.dtx
+ Extended support up to U+FFFFF after all, but not plane 16.
+ A bit more explanation in different places.
+ Some speed improvements (could be improved further)
+
+2021-10-17 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * unicodefonttable.dtx:
+ Extend support to the higher planes of Unicode by allowing a
+ range from U+0000 to U+EFFFF
+
+2021-10-08 Frank Mittelbach <Frank.Mittelbach@latex-project.org>
+
+ * unicodefonttable.dtx (subsection{Keys and their values}):
+ Added statistics-compare-format key.
+ Use longtable* from the caption package when not showing a
+ header with a \caption.
+
diff --git a/Master/texmf-dist/doc/latex/unicodefonttable/l3doc-TUB.cls b/Master/texmf-dist/doc/latex/unicodefonttable/l3doc-TUB.cls
new file mode 100644
index 00000000000..50a8a9a9d90
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/unicodefonttable/l3doc-TUB.cls
@@ -0,0 +1,2306 @@
+%%
+%% This is file `l3doc-TUB.cls'
+%%
+%% The original source files were:
+%%
+%% l3doc.dtx (with options: `class') + several manual changes!
+%%
+%% Copyright (C) 1990-2018 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:
+%%
+%% https://www.latex-project.org/lppl.txt
+%%
+%% File: l3doc.dtx Copyright (C) 1990-2018 The LaTeX3 project
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% This is really a temporary file intended for a single article
+%% written for TugBoat It is a copy of l3doc.cls with a couple of
+%% changes, nothing more. Eventually this will get replaced by a real
+%% class once l3doc.cls gets properly split into a class part and a
+%% support part.
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% If you use this for anything other than processing the documents it
+%% was meant for (which so far is 2) you are on your own :-)
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\RequirePackage{expl3,xparse,calc}
+\ProvidesExplClass{l3doc-TUB}{2021/03/02}{}
+ {L3 Experimental documentation class (special version for TUGboat with fixes)}
+\clist_new:N \g_docinput_clist
+\seq_new:N \g_doc_functions_seq
+\seq_new:N \g_doc_macros_seq
+\bool_new:N \l__codedoc_detect_internals_bool
+\bool_set_true:N \l__codedoc_detect_internals_bool
+\tl_new:N \l__codedoc_detect_internals_tl
+\tl_new:N \l__codedoc_detect_internals_cs_tl
+\coffin_new:N \l__codedoc_output_coffin
+\coffin_new:N \l__codedoc_functions_coffin
+\coffin_new:N \l__codedoc_descr_coffin
+\coffin_new:N \l__codedoc_syntax_coffin
+\box_new:N \g__codedoc_syntax_box
+\bool_new:N \l__codedoc_in_function_bool
+\bool_new:N \l__codedoc_long_name_bool
+\dim_new:N \l__codedoc_trial_width_dim
+\int_new:N \l__codedoc_nested_macro_int
+\bool_new:N \l__codedoc_macro_tested_bool
+\prop_new:N \g__codedoc_missing_tests_prop
+\seq_new:N \g__codedoc_not_tested_seq
+\seq_new:N \g__codedoc_testfiles_seq
+\bool_new:N \l__codedoc_macro_internal_set_bool
+\bool_new:N \l__codedoc_macro_internal_bool
+\bool_new:N \l__codedoc_macro_TF_bool
+\bool_new:N \l__codedoc_macro_pTF_bool
+\bool_new:N \l__codedoc_macro_noTF_bool
+\bool_new:N \l__codedoc_macro_EXP_bool
+\bool_new:N \l__codedoc_macro_rEXP_bool
+\bool_new:N \l__codedoc_macro_var_bool
+\tl_new:N \l__codedoc_override_module_tl
+\tl_set:Nn \l__codedoc_override_module_tl { \q_no_value }
+\tl_new:N \l__codedoc_macro_documented_tl
+\bool_new:N \g__codedoc_lmodern_bool
+\bool_new:N \g__codedoc_checkfunc_bool
+\bool_new:N \g__codedoc_checktest_bool
+\bool_new:N \g__codedoc_kernel_bool
+\tl_new:N \l__codedoc_tmpa_tl
+\tl_new:N \l__codedoc_tmpb_tl
+\int_new:N \l__codedoc_tmpa_int
+\int_new:N \l__codedoc_tmpa_seq
+\tl_new:N \l__codedoc_names_block_tl
+\seq_new:N \g__codedoc_variants_seq
+\bool_new:N \l__codedoc_names_verb_bool
+\seq_new:N \l__codedoc_names_seq
+\seq_new:N \g__codedoc_nested_names_seq
+\tl_const:Nx \c__codedoc_backslash_tl { \iow_char:N \\ }
+\exp_last_unbraced:NNo
+ \cs_new_eq:NN \c__codedoc_backslash_token { \c__codedoc_backslash_tl }
+\tl_new:N \l__codedoc_index_macro_tl
+\tl_new:N \l__codedoc_index_key_tl
+\tl_new:N \l__codedoc_index_module_tl
+\bool_new:N \l__codedoc_index_internal_bool
+\tl_new:N \g__codedoc_module_name_tl
+\tl_const:Nn \c__codedoc_iow_rule_tl
+ { ======================================== }
+\tl_const:Nn \c__codedoc_iow_mid_rule_tl
+ { -------------------------------------- }
+\box_new:N \l__codedoc_macro_box
+\box_new:N \l__codedoc_macro_index_box
+\int_new:N \l__codedoc_macro_int
+\tl_new:N \l__codedoc_cmd_tl
+\tl_new:N \l__codedoc_cmd_index_tl
+\tl_new:N \l__codedoc_cmd_module_tl
+\bool_new:N \l__codedoc_cmd_noindex_bool
+\bool_new:N \l__codedoc_cmd_replace_bool
+\bool_new:N \l__codedoc_in_implementation_bool
+\bool_new:N \g__codedoc_typeset_documentation_bool
+\bool_new:N \g__codedoc_typeset_implementation_bool
+\bool_set_true:N \g__codedoc_typeset_documentation_bool
+\bool_set_true:N \g__codedoc_typeset_implementation_bool
+\tl_new:N \g__codedoc_base_name_tl
+\prop_new:N \l__codedoc_variants_prop
+\clist_new:N \l__codedoc_function_label_clist
+\bool_new:N \l__codedoc_no_label_bool
+\tl_new:N \l__codedoc_date_added_tl
+\tl_new:N \l__codedoc_date_updated_tl
+\tl_new:N \l__codedoc_macro_argument_tl
+\cs_new_eq:NN \__codedoc_tmpa:w ?
+\cs_new_eq:NN \__codedoc_tmpb:w ?
+\cs_generate_variant:Nn \seq_set_split:Nnn { NoV }
+\cs_generate_variant:Nn \seq_gput_right:Nn { Nf }
+\cs_generate_variant:Nn \str_case:nn { fn }
+\cs_generate_variant:Nn \tl_count:n { f }
+\cs_generate_variant:Nn \tl_greplace_all:Nnn { Nx , Nno }
+\cs_generate_variant:Nn \tl_if_empty:nTF { f }
+\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNTF { o }
+\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNT { o }
+\cs_generate_variant:Nn \tl_if_head_eq_charcode:nNF { o }
+\cs_generate_variant:Nn \tl_if_head_eq_meaning:nNF { V }
+\cs_generate_variant:Nn \tl_if_in:nnTF { no , oo }
+\cs_generate_variant:Nn \tl_if_in:NnTF { No }
+\cs_generate_variant:Nn \tl_if_in:NnT { No }
+\cs_generate_variant:Nn \tl_if_in:NnF { No }
+\cs_generate_variant:Nn \tl_remove_all:Nn { Nx }
+\cs_generate_variant:Nn \tl_replace_all:Nnn { Nx , Nnx, No , Nno }
+\cs_generate_variant:Nn \tl_replace_once:Nnn { Noo }
+\cs_generate_variant:Nn \tl_to_str:n { f , o }
+\cs_generate_variant:Nn \prop_get:NnNTF { Nx }
+\cs_generate_variant:Nn \prop_put:Nnn { Nx }
+\cs_generate_variant:Nn \prop_gput:Nnn { NVx }
+\prg_new_protected_conditional:Npnn \__codedoc_if_almost_str:n #1 { TF , T , F }
+ {
+ \int_compare:nNnTF
+ { \tl_count:n {#1} }
+ < { \tl_count:f { \tl_to_str:f {#1} } }
+ { \prg_return_false: }
+ { \prg_return_true: }
+ }
+\cs_generate_variant:Nn \__codedoc_if_almost_str:nT { V }
+\cs_new_protected:Npn \__codedoc_trim_right:Nn #1#2
+ {
+ \cs_set:Npn \__codedoc_tmp:w ##1 #2 ##2 \q_stop { \exp_not:n {##1} }
+ \tl_set:Nx #1 { \exp_after:wN \__codedoc_tmp:w #1 #2 \q_stop }
+ }
+\cs_generate_variant:Nn \__codedoc_trim_right:Nn { No }
+\prg_new_protected_conditional:Npnn \__codedoc_str_if_begin:nn #1#2 { TF , T , F }
+ {
+ \tl_if_in:ooTF
+ { \exp_after:wN \scan_stop: \tl_to_str:n {#1} }
+ { \exp_after:wN \scan_stop: \tl_to_str:n {#2} }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+\prg_generate_conditional_variant:Nnn \__codedoc_str_if_begin:nn
+ { oo } { TF , T , F }
+\cs_new_protected:Npn \__codedoc_replace_at_at:N #1
+ {
+ \bool_if:NT \l__codedoc_in_implementation_bool
+ {
+ \bool_if:NT \l__codedoc_detect_internals_bool
+ { \__codedoc_detect_internals:N #1 }
+ }
+ \tl_if_empty:NF \g__codedoc_module_name_tl
+ {
+ \exp_args:NNo \__codedoc_replace_at_at_aux:Nn
+ #1 \g__codedoc_module_name_tl
+ }
+ }
+\cs_new_protected:Npx \__codedoc_replace_at_at_aux:Nn #1#2
+ {
+ \tl_replace_all:Nnn #1 { \token_to_str:N @ } { @ }
+ \tl_replace_all:Nnn #1 { \token_to_str:N _ } { _ }
+ \tl_replace_all:Nnn #1 { @ @ @ @ } { \token_to_str:N a a }
+ \tl_replace_all:Nnn #1 { _ _ @ @ } { _ _ #2 }
+ \tl_replace_all:Nnn #1 { _ @ @ } { _ _ #2 }
+ \tl_replace_all:Nnn #1 { @ @ } { _ _ #2 }
+ \tl_replace_all:Nnn #1 { \token_to_str:N a a } { @ @ }
+ }
+\group_begin:
+ \char_set_catcode_active:N \^^M
+ \cs_new_protected:Npn \__codedoc_detect_internals:N #1
+ {
+ \tl_set_eq:NN \l__codedoc_detect_internals_tl #1
+ \tl_replace_all:Non \l__codedoc_detect_internals_tl { \token_to_str:N _ } { _ }
+ \seq_set_split:NnV \l__codedoc_tmpa_seq { _ _ } \l__codedoc_detect_internals_tl
+ \seq_pop_left:NN \l__codedoc_tmpa_seq \l__codedoc_detect_internals_tl
+ \seq_map_variable:NNn \l__codedoc_tmpa_seq \l__codedoc_detect_internals_tl
+ {
+ \__codedoc_trim_right:No \l__codedoc_detect_internals_tl
+ \c_catcode_active_space_tl
+ \__codedoc_trim_right:Nn \l__codedoc_detect_internals_tl ^^M
+ \__codedoc_if_detect_internals_ok:NF \l__codedoc_detect_internals_tl
+ {
+ \tl_set_eq:NN \l__codedoc_detect_internals_cs_tl \l__codedoc_detect_internals_tl
+ \__codedoc_trim_right:Nn \l__codedoc_detect_internals_tl _
+ \__codedoc_trim_right:Nn \l__codedoc_detect_internals_tl :
+ \__codedoc_trim_right:No \l__codedoc_detect_internals_tl { \token_to_str:N : }
+ \msg_warning:nnxxx { l3doc-TUB } { foreign-internal }
+ { \tl_to_str:N \l__codedoc_detect_internals_cs_tl }
+ { \tl_to_str:N \l__codedoc_detect_internals_tl }
+ { \tl_to_str:N \g__codedoc_module_name_tl }
+ }
+ }
+ }
+\group_end:
+\prg_new_protected_conditional:Npnn \__codedoc_if_detect_internals_ok:N #1 { F }
+ {
+ \__codedoc_str_if_begin:ooTF {#1} { \g__codedoc_module_name_tl _ }
+ { \prg_return_true: }
+ {
+ \__codedoc_str_if_begin:ooTF {#1} { \g__codedoc_module_name_tl : }
+ { \prg_return_true: }
+ {
+ \bool_if:NTF \g__codedoc_kernel_bool
+ {
+ \__codedoc_str_if_begin:ooTF {#1} { kernel _ }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ { \prg_return_false: }
+ }
+ }
+ }
+\cs_new:Npn \__codedoc_signature_base_form:n #1
+ { \__codedoc_signature_base_form_aux:n #1 \q_stop }
+\cs_new:Npn \__codedoc_signature_base_form_aux:n #1
+ {
+ \str_case:nnTF {#1}
+ {
+ { N } { N }
+ { c } { N }
+ { n } { n }
+ { o } { n }
+ { f } { n }
+ { x } { n }
+ { V } { n }
+ { v } { n }
+ }
+ { \__codedoc_signature_base_form_aux:n }
+ { \__codedoc_signature_base_form_aux:w #1 }
+ }
+\cs_new:Npn \__codedoc_signature_base_form_aux:w #1 \q_stop
+ { \exp_not:n {#1} }
+\cs_new:Npn \__codedoc_predicate_from_base:n #1
+ {
+ \__codedoc_get_function_name:n {#1}
+ \tl_to_str:n { _p: }
+ \__codedoc_get_function_signature:n {#1}
+ }
+\cs_new:Npn \__codedoc_get_function_name:n #1
+ { \__codedoc_split_function_do:nn {#1} { \use_i:nnn } }
+\cs_new:Npn \__codedoc_get_function_signature:n #1
+ { \__codedoc_split_function_do:nn {#1} { \use_ii:nnn } }
+\cs_set_protected:Npn \__codedoc_tmpa:w #1
+ {
+ \cs_new:Npn \__codedoc_split_function_do:nn ##1
+ {
+ \exp_after:wN \__codedoc_split_function_auxi:w
+ \tl_to_str:n {##1} \q_mark \c_true_bool
+ #1 \q_mark \c_false_bool
+ \q_stop
+ }
+ \cs_new:Npn \__codedoc_split_function_auxi:w
+ ##1 #1 ##2 \q_mark ##3##4 \q_stop ##5
+ { \__codedoc_split_function_auxii:w {##5} ##1 \q_mark \q_stop {##2} ##3 }
+ \cs_new:Npn \__codedoc_split_function_auxii:w
+ ##1##2 \q_mark ##3 \q_stop
+ { ##1 {##2} }
+ }
+\exp_args:No \__codedoc_tmpa:w { \token_to_str:N : }
+\cs_generate_variant:Nn \__codedoc_split_function_do:nn { o }
+\cs_new_protected:Npn \__codedoc_key_get_base:nN #1#2
+ {
+ \__codedoc_if_almost_str:nTF {#1}
+ {
+ \__codedoc_key_get_base_TF:nN {#1} \l__codedoc_tmpa_tl
+ \tl_set:Nx #2
+ { \__codedoc_split_function_do:on \l__codedoc_tmpa_tl { \__codedoc_base_form_aux:nnN } }
+ }
+ { \tl_set:Nn #2 {#1} }
+ }
+\cs_new:Npx \__codedoc_key_get_base_TF:nN #1#2
+ {
+ \tl_set:Nx #2 { \exp_not:N \tl_to_str:n {#1} \scan_stop: }
+ \tl_if_in:NnTF #2 { \tl_to_str:n { F } \scan_stop: }
+ {
+ \tl_if_in:NnF #2 { \tl_to_str:n { TF } \scan_stop: }
+ {
+ \tl_replace_once:Nnn #2
+ { \tl_to_str:n { F } \scan_stop: }
+ { \tl_to_str:n { TF } \scan_stop: }
+ }
+ }
+ {
+ \tl_replace_once:Nnn #2
+ { \tl_to_str:n { T } \scan_stop: }
+ { \tl_to_str:n { TF } \scan_stop: }
+ }
+ \tl_remove_once:Nn #2 { \scan_stop: }
+ }
+\cs_new:Npn \__codedoc_base_form_aux:nnN #1#2#3
+ {
+ \exp_not:n {#1}
+ \bool_if:NT #3
+ {
+ \token_to_str:N :
+ \str_if_eq:nnTF { #1 ~ } { \exp_args }
+ { \exp_not:n {#2} }
+ { \__codedoc_signature_base_form:n {#2} }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_base_form_signature_do:nnn #1#2#3
+ {
+ \__codedoc_split_function_do:nn {#1}
+ { \__codedoc_base_form_aux:nnnnnN {#1} {#2} {#3} }
+ }
+\cs_new_protected:Npn \__codedoc_base_form_aux:nnnnnN #1#2#3#4#5#6
+ {
+ \bool_if:NTF #6
+ {
+ \tl_if_head_eq_charcode:nNTF {#4} :
+ { #2 {#1} }
+ {
+ \use:x
+ {
+ \exp_not:n {#3}
+ { \__codedoc_base_form_aux:nnN {#4} {#5} #6 }
+ }
+ {#4} {#5}
+ }
+ }
+ { #2 {#1} }
+ }
+\prg_new_conditional:Npnn \__codedoc_date_compare:nNn #1#2#3 { TF , T , F , p }
+ { \__codedoc_date_compare_aux:w #1--- \q_mark #2 #3--- \q_stop }
+\cs_new:Npn \__codedoc_date_compare_aux:w
+ #1 - #2 - #3 - #4 \q_mark #5 #6 - #7 - #8 - #9 \q_stop
+ {
+ \__codedoc_date_compare_aux:nnnNnnn
+ { \tl_if_empty:nTF {#1} { 0 } {#1} }
+ { \tl_if_empty:nTF {#2} { 0 } {#2} }
+ { \tl_if_empty:nTF {#3} { 0 } {#3} }
+ #5
+ { \tl_if_empty:nTF {#6} { 0 } {#6} }
+ { \tl_if_empty:nTF {#7} { 0 } {#7} }
+ { \tl_if_empty:nTF {#8} { 0 } {#8} }
+ }
+\cs_new:Npn \__codedoc_date_compare_aux:nnnNnnn #1#2#3#4#5#6#7
+ {
+ \int_compare:nNnTF {#1} = {#5}
+ {
+ \int_compare:nNnTF {#2} = {#6}
+ {
+ \int_compare:nNnTF {#3} #4 {#7}
+ { \prg_return_true: } { \prg_return_false: }
+ }
+ {
+ \int_compare:nNnTF {#2} #4 {#6}
+ { \prg_return_true: } { \prg_return_false: }
+ }
+ }
+ {
+ \int_compare:nNnTF {#1} #4 {#5}
+ { \prg_return_true: } { \prg_return_false: }
+ }
+ \use_none:n
+ \q_stop
+ }
+\cs_new:Npn \__codedoc_gprop_name:n #1 { g__codedoc ~ \tl_to_str:n {#1} }
+\cs_new:Npn \__codedoc_lseq_name:n #1 { l__codedoc ~ \tl_to_str:n {#1} }
+\msg_new:nnnn { l3doc-TUB } { no-signature-TF }
+ { Function/macro~'#1'~cannot~be~turned~into~a~conditional. }
+ {
+ A~function~or~macro~environment~with~option~pTF,~TF~or~noTF~
+ received~the~argument~'#1'.~This~function's~name~has~no~
+ ':'~hence~it~is~not~clear~where~to~add~'_p'~or~'TF'.~
+ Please~follow~expl3~naming~conventions.
+ }
+\msg_new:nnn { l3doc-TUB } { deprecated-function }
+ { The~deprecated~function(s)~'#1'~should~have~been~removed~on~#2. }
+\msg_new:nnn { l3doc-TUB } { date-format }
+ { The~date~'#1'~should~be~given~in~YYYY-MM-DD~format. }
+\msg_new:nnn { l3doc-TUB } { syntax-nested-function }
+ {
+ The~'syntax'~environment~should~be~used~in~the~
+ innermost~'function'~environment.
+ }
+\msg_new:nnn { l3doc-TUB } { multiple-syntax }
+ {
+ The~'syntax'~environment~should~only~be~used~once~in~
+ a~'function'~environment.
+ }
+\msg_new:nnn { l3doc-TUB } { deprecated-option }
+ { The~option~'#1'~has~been~deprecated~for~'#2'. }
+\msg_new:nnn { l3doc-TUB } { foreign-internal }
+ {
+ A~control~sequence~of~the~form~'...__#1'~was~used.~
+ It~should~only~be~used~in~the~module~'#2'
+ \tl_if_empty:nF {#3} { ,~not~in~'#3' } .
+ }
+\DeclareOption { a5paper } { \@latexerr { Option~not~supported } { } }
+\DeclareOption { full }
+ {
+ \bool_gset_true:N \g__codedoc_typeset_documentation_bool
+ \bool_gset_true:N \g__codedoc_typeset_implementation_bool
+ }
+\DeclareOption { onlydoc }
+ {
+ \bool_gset_true:N \g__codedoc_typeset_documentation_bool
+ \bool_gset_false:N \g__codedoc_typeset_implementation_bool
+ }
+\DeclareOption { check }
+ { \bool_gset_true:N \g__codedoc_checkfunc_bool }
+\DeclareOption { nocheck }
+ { \bool_gset_false:N \g__codedoc_checkfunc_bool }
+\DeclareOption { checktest }
+ { \bool_gset_true:N \g__codedoc_checktest_bool }
+\DeclareOption { nochecktest }
+ { \bool_gset_false:N \g__codedoc_checktest_bool }
+\DeclareOption { kernel }
+ { \bool_gset_true:N \g__codedoc_kernel_bool }
+\DeclareOption { stdmodule }
+ { \bool_gset_false:N \g__codedoc_kernel_bool }
+\DeclareOption { cm-default }
+ { \bool_gset_false:N \g__codedoc_lmodern_bool }
+\DeclareOption { lm-default }
+ { \bool_gset_true:N \g__codedoc_lmodern_bool }
+\DeclareOption* { \PassOptionsToClass { \CurrentOption } { ltugboat } }
+\ExecuteOptions { full, kernel, nocheck, nochecktest, lm-default }
+%%FMi \PassOptionsToClass { a4paper } { article }
+\msg_new:nnn { l3doc-TUB } { input-cfg }
+ { Local~config~file~l3doc-TUB.cfg~loaded. }
+\file_if_exist:nT { l3doc-TUB.cfg }
+ {
+ \file_input:nT { l3doc-TUB.cfg }
+ {
+ \cs_if_exist:cF { ExplMakeTitle }
+ { \msg_info:nn { l3doc-TUB } { input-cfg } }
+ }
+ }
+\ProcessOptions
+\LoadClass[final]{ltugboat}
+\RequirePackage{doc}
+
+\newcommand\bibname{References} % otherwise \bibname is undefined at \Finale
+\TBtocsectionspace=0pt plus 1pt
+
+\IndexPrologue
+ {\section*{Index}
+ \markboth{Index}{Index}
+ \addcontentsline{toc}{section}{Index}
+ \noindent
+ Underlined numbers point to the definition,
+ italicized numbers denote the pages where the
+ corresponding entry is described,
+ all others indicate the places where it is used.}
+%\EnableCrossrefs
+%\CodelineIndex
+
+\RequirePackage
+ {
+ microtype,
+ array,
+ alphalph,
+ amsmath,
+ amssymb,
+ booktabs,
+ color,
+ colortbl,
+ hologo,
+ enumitem,
+ pifont,
+ textcomp,
+ trace,
+ underscore,
+ csquotes,
+ fancyvrb,
+ verbatim
+ }
+\raggedbottom
+\bool_if:NT \g__codedoc_lmodern_bool
+ {
+ \RequirePackage[T1]{fontenc}
+ \RequirePackage{lmodern}
+ \group_begin:
+ \ttfamily
+ \DeclareFontShape{T1}{lmtt}{m}{it}{<->ec-lmtto10}{}
+ \group_end:
+ }
+
+\RequirePackage{hypdoc}
+
+%%FMi:
+\hypersetup{allcolors=black}
+
+\cs_gset:Npn \MakePrivateLetters
+ {
+ \char_set_catcode_letter:N \@
+ \char_set_catcode_letter:N \_
+ \char_set_catcode_letter:N \:
+ }
+\setcounter{StandardModuleDepth}{1}
+\@addtoreset{CodelineNo}{part}
+\tl_replace_once:Nnn \theCodelineNo
+ { \HDorg@theCodelineNo }
+ { \textcolor[gray]{0.5} { \sffamily\tiny\arabic{CodelineNo} } }
+\fvset{gobble=2}
+\cs_gset_eq:NN \verbatim \Verbatim
+\cs_gset_eq:NN \endverbatim \endVerbatim
+\cs_set_protected:Npn \ifnot@excluded
+ {
+ \exp_args:Nxx \expanded@notin
+ { \c__codedoc_backslash_tl \tl_to_str:N \macro@namepart , }
+ { \exp_args:NV \tl_to_str:n \index@excludelist }
+ }
+\cs_new:Npn \pdfstringnewline { : ~ }
+\DeclareExpandableDocumentCommand
+ { \__codedoc_pdfstring_newline:w } { s o m } { \pdfstringnewline #3 }
+\pdfstringdefDisableCommands
+ { \cs_set_eq:NN \\ \__codedoc_pdfstring_newline:w }
+\setlength \textwidth { 385pt }
+\addtolength \marginparwidth { 30pt }
+\addtolength \oddsidemargin { 20pt }
+\addtolength \evensidemargin { 20pt }
+\cs_new_eq:NN \__codedoc_oldlist:nn \list
+\cs_gset:Npn \list #1 #2
+ { \__codedoc_oldlist:nn {#1} { #2 \dim_zero:N \listparindent } }
+\setlength \parindent { 2em }
+\setlength \itemindent { 0pt }
+\setlength \parskip { 1pt plus 3pt minus 0pt }
+\tl_gset:Nn \partname {File}
+\@addtoreset{section}{part}
+\cs_gset:Npn \l@section #1#2
+ {
+ \ifnum \c@tocdepth >\z@
+ \addpenalty\@secpenalty
+ \addvspace{\TBtocsectionspace}%
+ \setlength\@tempdima{2.5em} % was 1.5em
+ \begingroup
+ \parindent \z@ \rightskip \@pnumwidth
+ \parfillskip -\@pnumwidth
+ \leavevmode \TBtocsectionfont
+ \advance\leftskip\@tempdima
+ \hskip -\leftskip
+ #1\nobreak\hfil \nobreak\hb@xt@\@pnumwidth{\hss #2}\par
+ \endgroup
+ \fi
+ }
+\cs_gset:Npn \l@subsection
+ { \@dottedtocline{2}{2.5em}{2.3em} } % #2 = 1.5em
+\AtBeginDocument
+ {
+ \MakeShortVerb \"
+ \MakeShortVerb \|
+ \onecolumn
+ \SelfDocumenting
+ }
+\AtEndDocument
+ {
+ \DeleteShortVerb \"
+ \DeleteShortVerb \|
+ }
+\providecommand*\eTeX{\hologo{eTeX}}
+\providecommand*\IniTeX{\hologo{iniTeX}}
+\providecommand*\Lua{Lua}
+\providecommand*\LuaTeX{\hologo{LuaTeX}}
+\providecommand*\pdfTeX{\hologo{pdfTeX}}
+\providecommand*\XeTeX{\hologo{XeTeX}}
+\providecommand*\pTeX{p\kern-.2em\hologo{TeX}}
+\providecommand*\upTeX{up\kern-.2em\hologo{TeX}}
+\providecommand*\epTeX{$\varepsilon$-\pTeX}
+\providecommand*\eupTeX{$\varepsilon$-\upTeX}
+\DeclareDocumentCommand \cmd { O{} m }
+ { \__codedoc_cmd:no {#1} { \token_to_str:N #2 } }
+\DeclareDocumentCommand \cs { O{} m }
+ { \__codedoc_cmd:no {#1} { \c__codedoc_backslash_tl #2 } }
+\DeclareDocumentCommand \tn { O{} m }
+ {
+ \__codedoc_cmd:no
+ { module = TeX , replace = false , #1 }
+ { \c__codedoc_backslash_tl #2 }
+ }
+\DeclareDocumentCommand \meta { m }
+ { \__codedoc_meta:n {#1} }
+\DeclareExpandableDocumentCommand
+ { \__codedoc_pdfstring_cmd:w } { o m } { \token_to_str:N #2 }
+\DeclareExpandableDocumentCommand
+ { \__codedoc_pdfstring_cs:w } { o m } { \textbackslash \tl_to_str:n {#2} }
+\cs_new:Npn \__codedoc_pdfstring_meta:w #1
+ { < \tl_to_str:n {#1} > }
+\pdfstringdefDisableCommands
+ {
+ \cs_set_eq:NN \cmd \__codedoc_pdfstring_cmd:w
+ \cs_set_eq:NN \cs \__codedoc_pdfstring_cs:w
+ \cs_set_eq:NN \tn \__codedoc_pdfstring_cs:w
+ \cs_set_eq:NN \meta \__codedoc_pdfstring_meta:w
+ }
+\newcommand\Arg[1]
+ { \texttt{\char`\{} \meta{#1} \texttt{\char`\}} }
+\providecommand\marg[1]{ \Arg{#1} }
+\providecommand\oarg[1]{ \texttt[ \meta{#1} \texttt] }
+\providecommand\parg[1]{ \texttt( \meta{#1} \texttt) }
+\DeclareRobustCommand \file {\nolinkurl}
+\DeclareRobustCommand \env {\texttt}
+\DeclareRobustCommand \pkg {\textsf}
+\DeclareRobustCommand \cls {\textsf}
+\NewDocumentCommand \EnableDocumentation { }
+ { \bool_gset_true:N \g__codedoc_typeset_documentation_bool }
+\NewDocumentCommand \EnableImplementation { }
+ { \bool_gset_true:N \g__codedoc_typeset_implementation_bool }
+\NewDocumentCommand \DisableDocumentation { }
+ { \bool_gset_false:N \g__codedoc_typeset_documentation_bool }
+\NewDocumentCommand \DisableImplementation { }
+ { \bool_gset_false:N \g__codedoc_typeset_implementation_bool }
+\NewDocumentEnvironment { documentation } { }
+ {
+ \bool_if:NTF \g__codedoc_typeset_documentation_bool
+ { \bool_set_false:N \l__codedoc_in_implementation_bool }
+ { \comment }
+ }
+ { \bool_if:NF \g__codedoc_typeset_documentation_bool { \endcomment } }
+\NewDocumentEnvironment { implementation } { }
+ {
+ \bool_if:NTF \g__codedoc_typeset_implementation_bool
+ { \bool_set_true:N \l__codedoc_in_implementation_bool }
+ { \comment }
+ }
+ { \bool_if:NF \g__codedoc_typeset_implementation_bool { \endcomment } }
+\DeclareDocumentEnvironment { variable } { O{} +v }
+ {
+ \bool_if:NTF \l__codedoc_in_implementation_bool
+ { \__codedoc_macro:nnw { var , #1 } {#2} }
+ { \__codedoc_function:nnw {#1} {#2} }
+ }
+ {
+ \bool_if:NTF \l__codedoc_in_implementation_bool
+ { \__codedoc_macro_end: }
+ { \__codedoc_function_end: }
+ }
+\DeclareDocumentEnvironment { function } { O{} +v }
+ { \__codedoc_function:nnw {#1} {#2} }
+ { \__codedoc_function_end: }
+\DeclareDocumentEnvironment { macro } { O{} +v }
+ { \__codedoc_macro:nnw {#1} {#2} }
+ { \__codedoc_macro_end: }
+\NewDocumentEnvironment { syntax } { }
+ { \__codedoc_syntax:w }
+ {
+ \__codedoc_syntax_end:
+ \ignorespacesafterend
+ }
+\NewDocumentEnvironment { texnote } { }
+ {
+ \endgraf
+ \vspace{3mm}
+ \small\textbf{\TeX~hackers~note:}
+ }
+ {
+ \vspace{3mm}
+ }
+\NewDocumentEnvironment { arguments } { }
+ {
+ \enumerate [
+ nolistsep ,
+ label = \texttt{\#\arabic*} ~ : ,
+ labelsep = * ,
+ ]
+ }
+ {
+ \endenumerate
+ }
+\NewDocumentCommand { \CodedocExplain } { }
+ { \CodedocExplainEXP \ \CodedocExplainREXP \ \CodedocExplainTF }
+\NewDocumentCommand { \CodedocExplainEXP } { }
+ {
+ \raisebox{\baselineskip}[0pt][0pt]{\hypertarget{expstar}{}}%
+ \__codedoc_typeset_exp:\ indicates~fully~expandable~functions,~which~
+ can~be~used~within~an~\texttt{x}-type~argument~(in~plain~
+ \TeX{}~terms,~inside~an~\cs{edef}),~as~well~as~within~an~
+ \texttt{f}-type~argument.
+ }
+\NewDocumentCommand { \CodedocExplainREXP } { }
+ {
+ \raisebox{\baselineskip}[0pt][0pt]{\hypertarget{rexpstar}{}}%
+ \__codedoc_typeset_rexp:\ indicates~
+ restricted~expandable~functions,~which~can~be~used~within~an~
+ \texttt{x}-type~argument~but~cannot~be~fully~expanded~within~an~
+ \texttt{f}-type~argument.
+ }
+\NewDocumentCommand { \CodedocExplainTF } { }
+ {
+ \raisebox{\baselineskip}[0pt][0pt]{\hypertarget{explTF}{}}%
+ \__codedoc_typeset_TF:\ indicates~conditional~(\texttt{if})~functions~
+ whose~variants~with~\texttt{T},~\texttt{F}~and~\texttt{TF}~
+ argument~specifiers~expect~different~
+ \enquote{true}/\enquote{false}~branches.
+ }
+\keys_define:nn { l3doc-TUB/cmd }
+ {
+ index .tl_set:N = \l__codedoc_cmd_index_tl ,
+ module .tl_set:N = \l__codedoc_cmd_module_tl ,
+ no-index .bool_set:N = \l__codedoc_cmd_noindex_bool ,
+ replace .bool_set:N = \l__codedoc_cmd_replace_bool ,
+ }
+\cs_new_protected:Npn \__codedoc_cmd:nn #1#2
+ {
+ \bool_set_false:N \l__codedoc_cmd_noindex_bool
+ \bool_set_true:N \l__codedoc_cmd_replace_bool
+ \tl_set:Nn \l__codedoc_cmd_index_tl { \q_no_value }
+ \tl_set:Nn \l__codedoc_cmd_module_tl { \q_no_value }
+ \keys_set:nn { l3doc-TUB/cmd } {#1}
+ \tl_set:Nn \l__codedoc_cmd_tl {#2}
+ \bool_if:NT \l__codedoc_cmd_replace_bool
+ {
+ \tl_set_rescan:Nnn \l__codedoc_tmpb_tl { } { _ }
+ \tl_replace_all:Non \l__codedoc_cmd_tl \l__codedoc_tmpb_tl { _ }
+ \__codedoc_replace_at_at:N \l__codedoc_cmd_tl
+ \tl_replace_all:Nno \l__codedoc_cmd_tl { _ } \l__codedoc_tmpb_tl
+ }
+ \mode_if_math:T { \mbox }
+ {
+ \verbatim@font
+ \__codedoc_if_almost_str:VT \l__codedoc_cmd_tl
+ {
+ \tl_set:Nx \l__codedoc_cmd_tl { \tl_to_str:N \l__codedoc_cmd_tl }
+ \tl_replace_all:Non \l__codedoc_cmd_tl
+ { \token_to_str:N _ } { \_ }
+ }
+ \tl_replace_all:Nnn \l__codedoc_cmd_tl { ~ } { \@xobeysp }
+ \l__codedoc_cmd_tl
+ \@
+ }
+ \bool_if:NF \l__codedoc_cmd_noindex_bool
+ {
+ \quark_if_no_value:NF \l__codedoc_cmd_index_tl
+ {
+ \tl_set:Nx \l__codedoc_cmd_tl
+ { \c_backslash_str \exp_not:o { \l__codedoc_cmd_index_tl } }
+ }
+
+ \exp_args:No \__codedoc_key_get:n { \l__codedoc_cmd_tl }
+ \quark_if_no_value:NF \l__codedoc_cmd_module_tl
+ {
+ \tl_set:Nx \l__codedoc_index_module_tl
+ { \tl_to_str:N \l__codedoc_cmd_module_tl }
+ }
+ \__codedoc_special_index_module:ooonN
+ { \l__codedoc_index_key_tl }
+ { \l__codedoc_index_macro_tl }
+ { \l__codedoc_index_module_tl }
+ { usage }
+ \l__codedoc_index_internal_bool
+ }
+ }
+\cs_generate_variant:Nn \__codedoc_cmd:nn { no }
+\cs_new_protected:Npn \__codedoc_meta:n #1
+ {
+ \tl_set:Nn \l__codedoc_tmpa_tl {#1}
+ \tl_map_inline:nn
+ { { 3 } { 4 } { 7 } { 8 } { 11 } { 12 } { 13 } }
+ {
+ \tl_set_rescan:Nnn \l__codedoc_tmpb_tl
+ { \char_set_catcode:nn { `_ } {##1} } { _ }
+ \tl_replace_all:Non \l__codedoc_tmpa_tl \l__codedoc_tmpb_tl
+ { \__codedoc_ensuremath_sb:n }
+ }
+ \exp_args:NV \__codedoc_meta_original:n \l__codedoc_tmpa_tl
+ }
+\cs_new_protected:Npn \__codedoc_ensuremath_sb:n #1
+ { \ensuremath { \sb {#1} } }
+\cs_new_protected:Npn \__codedoc_meta_original:n #1
+ {
+ \ensuremath \langle
+ \mode_if_math:T { \nfss@text }
+ {
+ \meta@font@select
+ \edef \meta@hyphen@restore
+ { \hyphenchar \the \font \the \hyphenchar \font }
+ \hyphenchar \font \m@ne
+ \language \l@nohyphenation
+ #1 \/
+ \meta@hyphen@restore
+ }
+ \ensuremath \rangle
+ }
+\cs_new_protected:Npn \__codedoc_typeset_exp:
+ { \hyperlink{expstar} {$\star$} }
+\cs_new_protected:Npn \__codedoc_typeset_rexp:
+ { \hyperlink{rexpstar} {\ding{73}} } % hollow star
+\cs_new_protected:Npn \__codedoc_typeset_TF:
+ {
+ \hyperlink{explTF}
+ {
+ \color{black}
+ \itshape TF
+ \makebox[0pt][r]
+ {
+ \color{red}
+ \underline { \phantom{\itshape TF} \kern-0.1em }
+ }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_typeset_aux:n #1
+ {
+ { \color[gray]{0.5} #1 }
+ }
+\cs_new_protected:Npn \__codedoc_get_hyper_target:nN #1#2
+ {
+ \tl_set:Nx #2 { \tl_to_str:n {#1} }
+ \tl_replace_all:Nxn #2 { \iow_char:N \_ } { / }
+ \tl_remove_all:Nx #2 { \iow_char:N \\ }
+ \tl_put_left:Nn #2 { doc/function// }
+ }
+\cs_generate_variant:Nn \__codedoc_get_hyper_target:nN { o , x }
+\cs_new_protected:Npn \__codedoc_names_get_seq:nN #1#2
+ {
+ \tl_set:Nx \l__codedoc_tmpa_tl { \tl_to_str:n {#1} }
+ \bool_if:NTF \l__codedoc_names_verb_bool
+ {
+ \seq_clear:N #2
+ \seq_put_right:NV #2 \l__codedoc_tmpa_tl
+ }
+ {
+ \tl_remove_all:Nx \l__codedoc_tmpa_tl
+ { \iow_char:N \^^M \iow_char:N \% }
+ \tl_remove_all:Nx \l__codedoc_tmpa_tl { \tl_to_str:n { ^ ^ A } }
+ \tl_remove_all:Nx \l__codedoc_tmpa_tl { \iow_char:N \^^I }
+ \tl_remove_all:Nx \l__codedoc_tmpa_tl { \iow_char:N \^^M }
+ \__codedoc_replace_at_at:N \l__codedoc_tmpa_tl
+ \exp_args:NNx \seq_set_from_clist:Nn #2
+ { \tl_to_str:N \l__codedoc_tmpa_tl }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_names_parse:
+ {
+ \tl_clear:N \l__codedoc_names_block_tl
+ \seq_map_function:NN
+ \l__codedoc_names_seq
+ \__codedoc_names_parse_one:n
+ }
+\cs_new_protected:Npn \__codedoc_names_parse_one:n #1
+ {
+ \__codedoc_split_function_do:nn {#1}
+ { \__codedoc_names_parse_one_aux:nnNn }
+ {#1}
+ }
+\cs_new_protected:Npn \__codedoc_names_parse_one_aux:nnNn #1#2#3#4
+ {
+ \bool_if:NTF #3
+ {
+ \tl_if_head_eq_charcode:nNTF {#2} :
+ { \__codedoc_names_parse_aux:nnn {#4} {#4} { \scan_stop: } }
+ {
+ \exp_args:Nx \__codedoc_names_parse_aux:nnn
+ { \__codedoc_base_form_aux:nnN {#1} {#2} #3 }
+ {#1} {#2}
+ }
+ }
+ {
+ \bool_if:NT \l__codedoc_macro_TF_bool
+ { \msg_error:nnx { l3doc-TUB } { no-signature-TF } {#4} }
+ \__codedoc_names_parse_aux:nnn {#4} {#4} { \scan_stop: }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_names_parse_aux:nnn #1
+ { \exp_args:Nc \__codedoc_names_parse_aux:Nnn { \__codedoc_lseq_name:n {#1} } }
+\cs_new_protected:Npn \__codedoc_names_parse_aux:Nnn #1#2#3
+ {
+ \tl_if_in:NnF \l__codedoc_names_block_tl {#1}
+ {
+ \tl_put_right:Nn \l__codedoc_names_block_tl {#1}
+ \seq_clear_new:N #1
+ \seq_put_right:Nn #1 {#2}
+ }
+ \seq_put_right:Nn #1 {#3}
+ }
+\cs_new_protected:Npn \__codedoc_names_typeset:
+ {
+ \tl_map_function:NN \l__codedoc_names_block_tl
+ \__codedoc_names_typeset_auxi:n
+ }
+\cs_new_protected:Npn \__codedoc_names_typeset_auxi:n #1
+ {
+ \seq_pop:NN #1 \l__codedoc_tmpa_tl
+ \tl_gset_eq:NN \g__codedoc_base_name_tl \l__codedoc_tmpa_tl
+ \tl_greplace_all:Nno \g__codedoc_base_name_tl
+ { ~ } { \c_catcode_other_space_tl }
+ \seq_get:NN #1 \l__codedoc_tmpa_tl
+ \str_if_eq:eeTF { \l__codedoc_tmpa_tl } { \scan_stop: }
+ {
+ \seq_gclear:N \g__codedoc_variants_seq
+ \__codedoc_names_typeset_auxii:x { \g__codedoc_base_name_tl }
+ }
+ {
+ \seq_gset_eq:NN \g__codedoc_variants_seq #1
+ \seq_gpop:NN \g__codedoc_variants_seq \l__codedoc_tmpb_tl
+ \__codedoc_names_typeset_auxii:x
+ { \g__codedoc_base_name_tl : \l__codedoc_tmpb_tl }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_names_typeset_auxii:n #1
+ {
+ \bool_if:NT \l__codedoc_macro_pTF_bool
+ {
+ \__codedoc_names_typeset_block:xN
+ { \__codedoc_predicate_from_base:n {#1} }
+ \c_false_bool
+ }
+ \bool_if:NT \l__codedoc_macro_noTF_bool
+ { \__codedoc_names_typeset_block:nN {#1} \c_false_bool }
+ \__codedoc_names_typeset_block:nN {#1} \l__codedoc_macro_TF_bool
+ }
+\cs_generate_variant:Nn \__codedoc_names_typeset_auxii:n { x }
+\cs_new_protected:Npn \__codedoc_names_typeset_block:nN
+ {
+ \int_compare:nNnTF \l__codedoc_nested_macro_int = 0
+ { \__codedoc_typeset_function_block:nN }
+ { \__codedoc_macro_typeset_block:nN }
+ }
+\cs_generate_variant:Nn \__codedoc_names_typeset_block:nN { x }
+\prg_new_conditional:Npnn \__codedoc_if_macro_internal:n #1 { p , T , F , TF }
+ {
+ \bool_if:NTF \l__codedoc_macro_internal_set_bool
+ {
+ \bool_if:NTF \l__codedoc_macro_internal_bool
+ { \prg_return_true: } { \prg_return_false: }
+ }
+ {
+ \tl_if_empty:fTF
+ {
+ \exp_after:wN \__codedoc_if_macro_internal_aux:w
+ \tl_to_str:n { #1 ~ __ }
+ }
+ { \prg_return_false: } { \prg_return_true: }
+ }
+ }
+\exp_last_unbraced:NNNNo
+ \cs_new:Npn \__codedoc_if_macro_internal_aux:w #1 { \tl_to_str:n { __ } } { }
+\cs_new_protected:Npn \__codedoc_names_block_base_map:N #1
+ {
+ \tl_map_inline:Nn \l__codedoc_names_block_tl
+ {
+ \group_begin:
+ \seq_set_eq:NN \l__codedoc_tmpa_seq ##1
+ \seq_pop:NN \l__codedoc_tmpa_seq \l__codedoc_tmpa_tl
+ \seq_get:NN \l__codedoc_tmpa_seq \l__codedoc_tmpb_tl
+ \exp_args:NNx
+ \group_end:
+ #1
+ {
+ \l__codedoc_tmpa_tl
+ \str_if_eq:eeF { \l__codedoc_tmpb_tl } { \scan_stop: }
+ { : \l__codedoc_tmpb_tl }
+ \bool_if:NT \l__codedoc_macro_TF_bool { TF }
+ }
+ }
+ }
+\keys_define:nn { l3doc-TUB/function }
+ {
+ TF .value_forbidden:n = true ,
+ TF .code:n =
+ {
+ \bool_set_true:N \l__codedoc_macro_TF_bool
+ } ,
+ EXP .value_forbidden:n = true ,
+ EXP .code:n =
+ {
+ \bool_set_true:N \l__codedoc_macro_EXP_bool
+ \bool_set_false:N \l__codedoc_macro_rEXP_bool
+ } ,
+ rEXP .value_forbidden:n = true ,
+ rEXP .code:n =
+ {
+ \bool_set_false:N \l__codedoc_macro_EXP_bool
+ \bool_set_true:N \l__codedoc_macro_rEXP_bool
+ } ,
+ pTF .value_forbidden:n = true ,
+ pTF .code:n =
+ {
+ \bool_set_true:N \l__codedoc_macro_pTF_bool
+ \bool_set_true:N \l__codedoc_macro_TF_bool
+ \bool_set_true:N \l__codedoc_macro_EXP_bool
+ \bool_set_false:N \l__codedoc_macro_rEXP_bool
+ } ,
+ noTF .value_forbidden:n = true ,
+ noTF .code:n =
+ {
+ \bool_set_true:N \l__codedoc_macro_noTF_bool
+ \bool_set_true:N \l__codedoc_macro_TF_bool
+ } ,
+ added .code:n = { \__codedoc_date_set:Nn \l__codedoc_date_added_tl {#1} },
+ updated .code:n = { \__codedoc_date_set:Nn \l__codedoc_date_updated_tl {#1} } ,
+ deprecated .code:n = { \__codedoc_deprecated_on:n {#1} } ,
+ tested .code:n = { } ,
+ label .code:n =
+ {
+ \clist_set:Nn \l__codedoc_function_label_clist {#1}
+ \bool_set_true:N \l__codedoc_no_label_bool
+ } ,
+ verb .value_forbidden:n = true ,
+ verb .bool_set:N = \l__codedoc_names_verb_bool ,
+ module .tl_set:N = \l__codedoc_override_module_tl ,
+ }
+\cs_new_protected:Npn \__codedoc_date_set:Nn #1#2
+ {
+ \tl_set:Nn #1 {#2}
+ \regex_replace_once:nnNF
+ { \A(\d\d\d\d)[-/](\d\d?)[-/](\d\d?)\Z } { \1-\2-\3 } #1
+ {
+ \msg_error:nnn { l3doc-TUB } { date-format } {#2}
+ \tl_set:Nn #1 { 1970-01-01 }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_deprecated_on:n #1
+ {
+ \__codedoc_date_set:Nn \l__codedoc_tmpa_tl {#1}
+ \exp_args:No \__codedoc_date_compare:nNnT
+ { \l__codedoc_tmpa_tl } < { \tex_year:D - \tex_month:D - \tex_day:D }
+ {
+ \msg_error:nnxx { l3doc-TUB } { deprecated-function }
+ { \tl_to_str:N \l__codedoc_macro_argument_tl }
+ { \l__codedoc_tmpa_tl }
+ }
+ \bool_set_true:N \l__codedoc_macro_internal_bool
+ \bool_set_true:N \l__codedoc_macro_internal_set_bool
+ }
+\cs_new_protected:Npn \__codedoc_function:nnw #1#2
+ {
+ \__codedoc_function_typeset_start:
+ \__codedoc_function_init:
+ \tl_set:Nn \l__codedoc_macro_argument_tl {#2}
+ \keys_set:nn { l3doc-TUB/function } {#1}
+ \__codedoc_names_get_seq:nN {#2} \l__codedoc_names_seq
+ \__codedoc_names_parse:
+ \__codedoc_function_typeset:
+ \__codedoc_function_reset:
+ \__codedoc_function_descr_start:w
+ }
+\cs_new_protected:Npn \__codedoc_function_end:
+ {
+ \__codedoc_function_descr_stop:
+ \__codedoc_function_assemble:
+ \__codedoc_function_typeset_stop:
+ }
+\cs_new_protected:Npn \__codedoc_function_typeset_start:
+ {
+ \par \bigskip \noindent
+ }
+\cs_new_protected:Npn \__codedoc_function_typeset_stop:
+ {
+ \par
+ \allowbreak
+ }
+\cs_new_protected:Npn \__codedoc_function_init:
+ {
+ \box_if_empty:NF \g__codedoc_syntax_box
+ { \msg_error:nn { l3doc-TUB } { syntax-nested-function } }
+ \coffin_clear:N \l__codedoc_descr_coffin
+ \box_gclear:N \g__codedoc_syntax_box
+ \coffin_clear:N \l__codedoc_syntax_coffin
+ \coffin_clear:N \l__codedoc_functions_coffin
+ \bool_set_false:N \l__codedoc_macro_TF_bool
+ \bool_set_false:N \l__codedoc_macro_pTF_bool
+ \bool_set_false:N \l__codedoc_macro_noTF_bool
+ \bool_set_false:N \l__codedoc_macro_EXP_bool
+ \bool_set_false:N \l__codedoc_macro_rEXP_bool
+ \bool_set_false:N \l__codedoc_no_label_bool
+ \bool_set_false:N \l__codedoc_names_verb_bool
+ \bool_set_true:N \l__codedoc_in_function_bool
+ \clist_clear:N \l__codedoc_function_label_clist
+ \tl_set:Nn \l__codedoc_override_module_tl { \q_no_value }
+ \char_set_active_eq:NN \< \__codedoc_shorthand_meta:
+ \char_set_catcode_active:N \<
+ }
+\cs_new_protected:Npn \__codedoc_shorthand_meta:
+ { \mode_if_math:TF { < } { \__codedoc_shorthand_meta:w } }
+\cs_new_protected_nopar:Npn \__codedoc_shorthand_meta:w #1 > { \meta {#1} }
+\cs_new_protected:Npn \__codedoc_function_reset:
+ {
+ \tl_set:Nn \l__codedoc_override_module_tl { \q_no_value }
+ }
+\cs_new_protected:Npn \__codedoc_function_typeset:
+ {
+ \dim_zero:N \l__codedoc_trial_width_dim
+ \hcoffin_set:Nn \l__codedoc_functions_coffin { \__codedoc_typeset_functions: }
+ \dim_set:Nn \l__codedoc_trial_width_dim
+ { \box_wd:N \l__codedoc_functions_coffin }
+ \bool_set:Nn \l__codedoc_long_name_bool
+ { \dim_compare_p:nNn \l__codedoc_trial_width_dim > {\marginparwidth + 1cm} } % FMi crude fix
+ }
+\cs_new_protected:Npn \__codedoc_function_descr_start:w
+ {
+ \vcoffin_set:Nnw \l__codedoc_descr_coffin { \textwidth }
+ \noindent \ignorespaces
+ }
+\cs_new_protected:Npn \__codedoc_function_descr_stop:
+ { \vcoffin_set_end: }
+\cs_new_protected:Npn \__codedoc_function_assemble:
+ {
+ \hcoffin_set:Nn \l__codedoc_syntax_coffin
+ { \box_use_drop:N \g__codedoc_syntax_box }
+ \bool_if:NTF \l__codedoc_long_name_bool
+ {
+ \coffin_join:NnnNnnnn
+ \l__codedoc_output_coffin {hc} {vc}
+ \l__codedoc_syntax_coffin {l} {T}
+ {0pt} {0pt}
+ \coffin_join:NnnNnnnn
+ \l__codedoc_output_coffin {l} {t}
+ \l__codedoc_functions_coffin {r} {t}
+ {-\marginparsep} {0pt}
+ \coffin_join:NnnNnnnn
+ \l__codedoc_output_coffin {l} {b}
+ \l__codedoc_descr_coffin {l} {t}
+ {0.75\marginparwidth + \marginparsep} {-\medskipamount}
+ \coffin_typeset:Nnnnn \l__codedoc_output_coffin
+ {\l__codedoc_descr_coffin-l} {\l__codedoc_descr_coffin-t}
+ {0pt} {0pt}
+ }
+ {
+ \coffin_join:NnnNnnnn
+ \l__codedoc_output_coffin {hc} {vc}
+ \l__codedoc_syntax_coffin {l} {t}
+ {0pt} {0pt}
+ \coffin_join:NnnNnnnn
+ \l__codedoc_output_coffin {l} {b}
+ \l__codedoc_descr_coffin {l} {t}
+ {0pt} {-\medskipamount}
+ \coffin_join:NnnNnnnn
+ \l__codedoc_output_coffin {l} {t}
+ \l__codedoc_functions_coffin {r} {t}
+ {-\marginparsep} {0pt}
+ \coffin_typeset:Nnnnn \l__codedoc_output_coffin
+ {\l__codedoc_syntax_coffin-l} {\l__codedoc_syntax_coffin-T}
+ {0pt} {0pt}
+ }
+ }
+\cs_new_protected:Npn \__codedoc_typeset_functions:
+ {
+ \small\ttfamily
+ \HD@savedestfalse
+ \HD@target
+ \Hy@MakeCurrentHref { HD. \int_use:N \c@HD@hypercount }
+ \begin{tabular} [t] { @{} l @{} >{\hspace{\tabcolsep}} r @{} }
+ \toprule
+ \__codedoc_function_extra_labels:
+ \__codedoc_names_typeset:
+ \__codedoc_typeset_dates:
+ \bottomrule
+ \end{tabular}
+ \normalfont\normalsize
+ }
+\cs_new_protected:Npn \__codedoc_typeset_function_block:nN #1#2
+ {
+ \__codedoc_function_index:x
+ { #1 \bool_if:NT #2 { \tl_to_str:n {TF} } }
+ \__codedoc_function_label:xN {#1} #2
+ #1
+ \bool_if:NT #2 { \__codedoc_typeset_TF: }
+ \__codedoc_typeset_expandability:
+ \seq_if_empty:NF \g__codedoc_variants_seq
+ { \__codedoc_typeset_variant_list:nN {#1} #2 }
+ \\
+ }
+\cs_generate_variant:Nn \__codedoc_typeset_function_block:nN { x }
+\cs_new_protected:Npn \__codedoc_function_index:n #1
+ {
+ \seq_gput_right:Nn \g_doc_functions_seq {#1}
+ \__codedoc_special_index:nn {#1} { usage }
+ }
+\cs_generate_variant:Nn \__codedoc_function_index:n { x }
+\cs_new_protected:Npn \__codedoc_typeset_expandability:
+ {
+ &
+ \bool_if:NT \l__codedoc_macro_EXP_bool { \__codedoc_typeset_exp: }
+ \bool_if:NT \l__codedoc_macro_rEXP_bool { \__codedoc_typeset_rexp: }
+ }
+\cs_new_protected:Npn \__codedoc_typeset_variant_list:nN #1#2
+ {
+ \\
+ \__codedoc_typeset_aux:n { \__codedoc_get_function_name:n {#1} }
+ :
+ \int_compare:nTF { \seq_count:N \g__codedoc_variants_seq == 1 }
+ { \seq_use:Nn \g__codedoc_variants_seq { } }
+ {
+ \textrm(
+ \seq_use:Nn \g__codedoc_variants_seq { \textrm| }
+ \textrm)
+ }
+ \bool_if:NT #2 { \__codedoc_typeset_TF: }
+ \__codedoc_typeset_expandability:
+ }
+\cs_new_protected:Npn \__codedoc_function_extra_labels:
+ {
+ \bool_if:NT \l__codedoc_no_label_bool
+ {
+ \clist_map_inline:Nn \l__codedoc_function_label_clist
+ {
+ \__codedoc_get_hyper_target:oN { \token_to_str:N ##1 }
+ \l__codedoc_tmpa_tl
+ \exp_args:No \label { \l__codedoc_tmpa_tl }
+ }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_function_label:nN #1#2
+ {
+ \bool_if:NF \l__codedoc_no_label_bool
+ {
+ \__codedoc_get_hyper_target:xN
+ {
+ \exp_not:n {#1}
+ \bool_if:NT #2 { \tl_to_str:n {TF} }
+ }
+ \l__codedoc_tmpa_tl
+ \exp_args:No \label { \l__codedoc_tmpa_tl }
+ }
+ }
+\cs_generate_variant:Nn \__codedoc_function_label:nN { x }
+\cs_new:Npn \__codedoc_typeset_dates:
+ {
+ \bool_lazy_and:nnF
+ { \tl_if_empty_p:N \l__codedoc_date_added_tl }
+ { \tl_if_empty_p:N \l__codedoc_date_updated_tl }
+ { \midrule }
+ \tl_if_empty:NF \l__codedoc_date_added_tl
+ {
+ \multicolumn { 2 } { @{} r @{} }
+ { \scriptsize New: \, \l__codedoc_date_added_tl } \\
+ }
+
+ \tl_if_empty:NF \l__codedoc_date_updated_tl
+ {
+ \multicolumn { 2 } { @{} r @{} }
+ { \scriptsize Updated: \, \l__codedoc_date_updated_tl } \\
+ }
+ }
+\dim_new:N \l__codedoc_syntax_dim
+\cs_new_protected:Npn \__codedoc_syntax:w
+ {
+ \box_if_empty:NF \g__codedoc_syntax_box
+ { \msg_error:nn { l3doc-TUB } { multiple-syntax } }
+ \dim_set:Nn \l__codedoc_syntax_dim
+ {
+ \textwidth
+ \bool_if:NT \l__codedoc_long_name_bool
+ { + 0.75 \marginparwidth - \l__codedoc_trial_width_dim }
+ }
+ \hbox_gset:Nw \g__codedoc_syntax_box
+ \small \ttfamily
+ \arrayrulecolor{white}
+ \begin{tabular} { @{} l @{} }
+ \toprule
+ \begin{minipage}[t]{\l__codedoc_syntax_dim}
+ \raggedright
+ \obeyspaces
+ \obeylines
+ }
+\cs_new_protected:Npn \__codedoc_syntax_end:
+ {
+ \end{minipage}
+ \end{tabular}
+ \arrayrulecolor{black}
+ \hbox_gset_end:
+ \bool_if:NF \l__codedoc_in_function_bool
+ {
+ \begin{quote}
+ \mode_leave_vertical:
+ \box_use_drop:N \g__codedoc_syntax_box
+ \end{quote}
+ }
+ }
+\keys_define:nn { l3doc-TUB/macro }
+ {
+ aux .value_forbidden:n = true ,
+ aux .code:n =
+ {
+ \msg_warning:nnnn { l3doc-TUB } { deprecated-option }
+ { aux } { function/macro }
+ } ,
+ internal .value_forbidden:n = true ,
+ internal .code:n =
+ {
+ \bool_set_true:N \l__codedoc_macro_internal_bool
+ \bool_set_true:N \l__codedoc_macro_internal_set_bool
+ } ,
+ int .value_forbidden:n = true ,
+ int .code:n =
+ {
+ \bool_set_true:N \l__codedoc_macro_internal_bool
+ \bool_set_true:N \l__codedoc_macro_internal_set_bool
+ } ,
+ var .value_forbidden:n = true ,
+ var .code:n =
+ { \bool_set_true:N \l__codedoc_macro_var_bool } ,
+ TF .value_forbidden:n = true ,
+ TF .code:n =
+ { \bool_set_true:N \l__codedoc_macro_TF_bool } ,
+ pTF .value_forbidden:n = true ,
+ pTF .code:n =
+ {
+ \bool_set_true:N \l__codedoc_macro_TF_bool
+ \bool_set_true:N \l__codedoc_macro_pTF_bool
+ \bool_set_true:N \l__codedoc_macro_EXP_bool
+ \bool_set_false:N \l__codedoc_macro_rEXP_bool
+ } ,
+ noTF .value_forbidden:n = true ,
+ noTF .code:n =
+ {
+ \bool_set_true:N \l__codedoc_macro_TF_bool
+ \bool_set_true:N \l__codedoc_macro_noTF_bool
+ } ,
+ EXP .value_forbidden:n = true ,
+ EXP .code:n =
+ {
+ \bool_set_true:N \l__codedoc_macro_EXP_bool
+ \bool_set_false:N \l__codedoc_macro_rEXP_bool
+ } ,
+ rEXP .value_forbidden:n = true ,
+ rEXP .code:n =
+ {
+ \bool_set_false:N \l__codedoc_macro_EXP_bool
+ \bool_set_true:N \l__codedoc_macro_rEXP_bool
+ } ,
+ tested .code:n =
+ {
+ \bool_set_true:N \l__codedoc_macro_tested_bool
+ } ,
+ added .code:n = {} , % TODO
+ updated .code:n = {} , % TODO
+ deprecated .code:n = { \__codedoc_deprecated_on:n {#1} } ,
+ verb .bool_set:N = \l__codedoc_names_verb_bool ,
+ module .tl_set:N = \l__codedoc_override_module_tl ,
+ documented-as .tl_set:N = \l__codedoc_macro_documented_tl ,
+ }
+\cs_new_protected:Npn \__codedoc_macro:nnw #1#2
+ {
+ \__codedoc_macro_init:
+ \tl_set:Nn \l__codedoc_macro_argument_tl {#2}
+ \keys_set:nn { l3doc-TUB/macro } {#1}
+ \__codedoc_names_get_seq:nN {#2} \l__codedoc_names_seq
+ \__codedoc_names_parse:
+ \__codedoc_macro_save_names:
+ \__codedoc_names_typeset:
+ \__codedoc_macro_dump:
+ \__codedoc_macro_reset:
+ }
+\cs_new_protected:Npn \__codedoc_macro_init:
+ {
+ \int_incr:N \l__codedoc_nested_macro_int
+ \bool_set_false:N \l__codedoc_macro_internal_bool
+ \bool_set_false:N \l__codedoc_macro_internal_set_bool
+ \bool_set_false:N \l__codedoc_macro_TF_bool
+ \bool_set_false:N \l__codedoc_macro_pTF_bool
+ \bool_set_false:N \l__codedoc_macro_noTF_bool
+ \bool_set_false:N \l__codedoc_macro_EXP_bool
+ \bool_set_false:N \l__codedoc_macro_rEXP_bool
+ \bool_set_false:N \l__codedoc_macro_var_bool
+ \bool_set_false:N \l__codedoc_macro_tested_bool
+ \bool_set_false:N \l__codedoc_names_verb_bool
+ \tl_set:Nn \l__codedoc_override_module_tl { \q_no_value }
+ \tl_clear:N \l__codedoc_macro_documented_tl
+ \cs_set_eq:NN \testfile \__codedoc_print_testfile:n
+ \box_clear:N \l__codedoc_macro_index_box
+ \vbox_set:Nn \l__codedoc_macro_box
+ {
+ \hbox:n
+ {
+ \strut
+ \int_compare:nNnT \l__codedoc_macro_int = 0
+ { \HD@target }
+ }
+ \vskip \int_eval:n { \l__codedoc_macro_int - 1 } \baselineskip
+ }
+ }
+\cs_new_protected:Npn \__codedoc_macro_reset:
+ {
+ \tl_set:Nn \l__codedoc_override_module_tl { \q_no_value }
+ }
+\cs_new_protected:Npn \__codedoc_macro_save_names:
+ {
+ \tl_if_empty:NTF \l__codedoc_macro_documented_tl
+ { \__codedoc_names_block_base_map:N \__codedoc_macro_save_names_aux:n }
+ {
+ \seq_gput_right:Nf \g__codedoc_nested_names_seq
+ { \exp_after:wN \token_to_str:N \l__codedoc_macro_documented_tl }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_macro_save_names_aux:n #1
+ { \seq_gput_right:Nn \g__codedoc_nested_names_seq {#1} }
+\cs_new_protected:Npn \__codedoc_macro_dump:
+ {
+ \topsep\MacroTopsep
+ \trivlist
+ \cs_set:Npn \makelabel ##1
+ {
+ \llap
+ {
+ \hbox_unpack_drop:N \l__codedoc_macro_index_box
+ \vtop to \baselineskip
+ {
+ \vbox_unpack_drop:N \l__codedoc_macro_box
+ \vss
+ }
+ }
+ }
+ \item [ ]
+ }
+\cs_new_protected:Npn \__codedoc_macro_typeset_block:nN #1#2
+ {
+ \__codedoc_macro_single:nNN {#1} \c_true_bool #2
+ \seq_if_empty:NF \g__codedoc_variants_seq
+ {
+ \__codedoc_macro_typeset_variant_list:xN
+ { \__codedoc_get_function_name:n {#1} } #2
+ }
+ }
+\cs_generate_variant:Nn \__codedoc_macro_typeset_block:nN { x }
+\cs_new_protected:Npn \__codedoc_macro_typeset_variant_list:nN #1#2
+ {
+ \seq_map_inline:Nn \g__codedoc_variants_seq
+ { \__codedoc_macro_single:nNN { #1 : ##1 } \c_false_bool #2 }
+ }
+\cs_generate_variant:Nn \__codedoc_macro_typeset_variant_list:nN { x }
+\cs_new_protected:Npn \__codedoc_macro_single:nNN #1#2#3
+ {
+ \tl_set:Nn \saved@macroname {#1}
+ \__codedoc_macro_typeset_one:nN {#1} #3
+ \bool_if:NT #3 { \DoNotIndex {#1} }
+ \exp_args:Nx \__codedoc_macro_index:nN
+ { #1 \bool_if:NT #3 { \tl_to_str:n { TF } } }
+ #2
+ }
+\cs_new_protected:Npn \__codedoc_macro_index:nN #1#2
+ {
+ \DoNotIndex {#1}
+ \bool_if:NT #2
+ {
+ \__codedoc_if_macro_internal:nF {#1}
+ { \seq_gput_right:Nn \g_doc_macros_seq {#1} }
+ \hbox_set:Nw \l__codedoc_macro_index_box
+ \hbox_unpack_drop:N \l__codedoc_macro_index_box
+ \int_gincr:N \c@CodelineNo
+ \__codedoc_special_index:nn {#1} { main }
+ \int_gdecr:N \c@CodelineNo
+ \exp_args:NNNo \hbox_set_end:
+ \tl_set:Nn \saved@indexname { \l__codedoc_index_key_tl }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_macro_typeset_one:nN #1#2
+ {
+ \vbox_set:Nn \l__codedoc_macro_box
+ {
+ \vbox_unpack_drop:N \l__codedoc_macro_box
+ \hbox { \llap { \__codedoc_print_macroname:nN {#1} #2 \ } }
+ }
+ \int_incr:N \l__codedoc_macro_int
+ }
+\cs_new_protected:Npn \__codedoc_print_macroname:nN #1#2
+ {
+ \strut
+ \__codedoc_get_hyper_target:xN
+ {
+ \exp_not:n {#1}
+ \bool_if:NT #2 { \tl_to_str:n {TF} }
+ }
+ \l__codedoc_tmpa_tl
+ \cs_if_exist:cTF { r@ \l__codedoc_tmpa_tl }
+ { \exp_last_unbraced:NNo \hyperref [ \l__codedoc_tmpa_tl ] }
+ { \use:n }
+ {
+ \int_compare:nTF { \str_count:n {#1} <= 28 }
+ { \MacroFont } { \MacroLongFont }
+ \tl_set:Nn \l__codedoc_tmpa_tl {#1}
+ \tl_replace_all:Nno \l__codedoc_tmpa_tl
+ { ~ } { \c_catcode_other_space_tl }
+ \__codedoc_macroname_prefix:o \l__codedoc_tmpa_tl
+ \__codedoc_macroname_suffix:N #2
+ }
+ }
+\cs_new_protected:Npn \__codedoc_macroname_prefix:n #1
+ {
+ \__codedoc_if_macro_internal:nTF {#1}
+ { \__codedoc_typeset_aux:n {#1} } {#1}
+ }
+\cs_generate_variant:Nn \__codedoc_macroname_prefix:n { o }
+\cs_new_protected:Npn \__codedoc_macroname_suffix:N #1
+ { \bool_if:NTF #1 { \__codedoc_typeset_TF: } { } }
+\providecommand \MacroLongFont
+ {
+ \fontfamily{lmtt}\fontseries{lc}\small
+ }
+\cs_new_protected:Npn \__codedoc_print_testfile:n #1
+ {
+ \bool_set_true:N \l__codedoc_macro_tested_bool
+ \tl_if_eq:nnF {#1} {*}
+ {
+ \seq_if_in:NnF \g__codedoc_testfiles_seq {#1}
+ {
+ \seq_gput_right:Nn \g__codedoc_testfiles_seq {#1}
+ \par
+ \__codedoc_print_testfile_aux:n {#1}
+ }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_print_testfile_aux:n #1
+ {
+ \footnotesize
+ (
+ \textit
+ {
+ The~ test~ suite~ for~ this~ command,~
+ and~ others~ in~ this~ file,~ is~ \textsf{#1}
+ }.
+ )\par
+ }
+\DeclareDocumentCommand \TestFiles {m}
+ {
+ \par
+ \textit
+ {
+ The~ following~ test~ files~ are~
+ used~ for~ this~ code:~ \textsf{#1}.
+ }
+ \par \ignorespaces
+ }
+\DeclareDocumentCommand \UnitTested { } { \testfile* }
+\DeclareDocumentCommand \TestMissing { m }
+ { \__codedoc_test_missing:n {#1} }
+\cs_new_protected:Npn \__codedoc_test_missing:n #1
+ {
+ \__codedoc_test_missing_aux:Nxn
+ \g__codedoc_missing_tests_prop
+ { \seq_use:Nn \l__codedoc_names_seq { , } }
+ { { \g_file_curr_name_str \iow_char:N \ (#1) } }
+ }
+\cs_new_protected:Npn \__codedoc_test_missing_aux:Nnn #1#2#3
+ {
+ \prop_get:NnNTF #1 {#2} \l__codedoc_tmpa_tl
+ { \tl_put_right:Nn \l__codedoc_tmpa_tl { , #3 } }
+ { \tl_set:Nn \l__codedoc_tmpa_tl {#3} }
+ \prop_put:Nno #1 {#2} \l__codedoc_tmpa_tl
+ }
+\cs_generate_variant:Nn \__codedoc_test_missing_aux:Nnn { Nx }
+\cs_new_protected:Npn \__codedoc_macro_end:
+ {
+ \endtrivlist
+ \__codedoc_macro_end_check_tested:
+ \int_compare:nNnT \l__codedoc_nested_macro_int = 1
+ { \__codedoc_macro_end_style:n { \__codedoc_print_end_definition: } }
+ }
+\cs_new_protected:Npn \__codedoc_macro_end_check_tested:
+ {
+ \bool_lazy_all:nT
+ {
+ { \g__codedoc_checktest_bool }
+ { ! \l__codedoc_macro_var_bool }
+ { ! \l__codedoc_macro_tested_bool }
+ }
+ {
+ \seq_set_filter:NNn \l__codedoc_tmpa_seq \l__codedoc_names_seq
+ { ! \__codedoc_if_macro_internal_p:n {##1} }
+ \seq_gput_right:Nx \g__codedoc_not_tested_seq
+ {
+ \seq_use:Nn \l__codedoc_tmpa_seq { , }
+ \bool_if:NTF \l__codedoc_macro_pTF_bool {~(pTF)}
+ { \bool_if:NT \l__codedoc_macro_TF_bool {~(TF)} }
+ }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_macro_end_style:n #1
+ {
+ \nobreak \noindent
+ { \footnotesize ( \emph{#1} ) \par }
+ }
+\cs_new_protected:Npn \__codedoc_macro_end_wrap_item:n #1
+ {
+ \tl_set:Nn \l__codedoc_tmpa_tl {#1}
+ \tl_replace_all:Non \l__codedoc_tmpa_tl
+ { \token_to_str:N _ } { \_ }
+ \texttt { \l__codedoc_tmpa_tl }
+ }
+\cs_new_protected:Npn \__codedoc_print_end_definition:
+ {
+ \seq_set_map:NNn \l__codedoc_tmpa_seq
+ \g__codedoc_nested_names_seq
+ { \exp_not:n { \__codedoc_macro_end_wrap_item:n {##1} } }
+ End~ definition~ for~
+ \int_compare:nTF { \seq_count:N \l__codedoc_tmpa_seq <= 3 }
+ {
+ \seq_use:Nnnn \l__codedoc_tmpa_seq
+ { \,~and~ } { \,,~ } { \,,~and~ }
+ }
+ { \seq_item:Nn \l__codedoc_tmpa_seq {1}\,~and~others }
+ \@.
+ \__codedoc_print_documented:
+ }
+\cs_new_protected:Npn \__codedoc_print_documented:
+ {
+ \seq_gset_filter:NNn \g__codedoc_nested_names_seq
+ \g__codedoc_nested_names_seq
+ { ! \__codedoc_if_macro_internal_p:n {##1} }
+ \seq_if_empty:NF \g__codedoc_nested_names_seq
+ {
+ \int_set:Nn \l__codedoc_tmpa_int
+ { \seq_count:N \g__codedoc_nested_names_seq }
+ \int_compare:nNnTF \l__codedoc_tmpa_int = 1 {~This~} {~These~}
+ \bool_if:NTF \l__codedoc_macro_var_bool {variable} {function}
+ \int_compare:nNnTF \l__codedoc_tmpa_int = 1 {~is~} {s~are~}
+ documented~on~page~
+ \__codedoc_get_hyper_target:xN
+ { \seq_item:Nn \g__codedoc_nested_names_seq { 1 } }
+ \l__codedoc_tmpa_tl
+ \exp_args:Nx \pageref { \l__codedoc_tmpa_tl } .
+ }
+ \seq_gclear:N \g__codedoc_nested_names_seq
+ }
+\newcommand*{\DescribeOption}
+ {
+ \leavevmode
+ \@bsphack
+ \begingroup
+ \MakePrivateLetters
+ \Describe@Option
+ }
+\newcommand*{\Describe@Option}[1]
+ {
+ \endgroup
+ \marginpar{
+ \raggedleft
+ \PrintDescribeEnv{#1}
+ }
+ \SpecialOptionIndex{#1}
+ \@esphack
+ \ignorespaces
+ }
+\newcommand*{\SpecialOptionIndex}[1]
+ {
+ \@bsphack
+ \begingroup
+ \HD@target
+ \let\HDorg@encapchar\encapchar
+ \edef\encapchar usage
+ {
+ \HDorg@encapchar hdclindex{\the\c@HD@hypercount}{usage}
+ }
+ \index
+ {
+ #1\actualchar{\protect\ttfamily#1}~(option)
+ \encapchar usage
+ }
+ \index
+ {
+ options:\levelchar#1\actualchar{\protect\ttfamily#1}
+ \encapchar usage
+ }
+ \endgroup
+ \@esphack
+ }
+\font \manual = manfnt \scan_stop:
+\cs_gset:Npn \dbend { {\manual\char127} }
+\newenvironment {danger}
+ {
+ \begin{trivlist}\item[]\noindent
+ \begingroup\hangindent=2pc\hangafter=-2
+ \cs_set:Npn \par{\endgraf\endgroup}
+ \hbox to0pt{\hskip-\hangindent\dbend\hfill}\ignorespaces
+ }
+ {
+ \par\end{trivlist}
+ }
+\newenvironment {ddanger}
+ {
+ \begin{trivlist}\item[]\noindent
+ \begingroup\hangindent=3.5pc\hangafter=-2
+ \cs_set:Npn \par{\endgraf\endgroup}
+ \hbox to0pt{\hskip-\hangindent\dbend\kern2pt\dbend\hfill}\ignorespaces
+ }{
+ \par\end{trivlist}
+ }
+\newenvironment{TemplateInterfaceDescription}[1]
+ {
+ \subsection{The~object~type~`#1'}
+ \begingroup
+ \@beginparpenalty\@M
+ \description
+ \def\TemplateArgument##1##2{\item[Arg:~##1]##2\par}
+ \def\TemplateSemantics
+ {
+ \enddescription\endgroup
+ \subsubsection*{Semantics:}
+ }
+ }
+ {
+ \par\bigskip
+ }
+\newenvironment{TemplateDescription}[2]
+ {
+ \subsection{The~template~`#2'~(object~type~#1)}
+ \subsubsection*{Attributes:}
+ \begingroup
+ \@beginparpenalty\@M
+ \description
+ \def\TemplateKey##1##2##3##4
+ {
+ \item[##1~(##2)]##3%
+ \ifx\TemplateKey##4\TemplateKey\else
+ \hfill\penalty500\hbox{}\hfill Default:~##4%
+ \nobreak\hskip-\parfillskip\hskip0pt\relax
+ \fi
+ \par
+ }
+ \def\TemplateSemantics
+ {
+ \enddescription\endgroup
+ \subsubsection*{Semantics~\&~Comments:}
+ }
+ }
+ { \par \bigskip }
+\newenvironment{InstanceDescription}[4][xxxxxxxxxxxxxxx]
+ {
+ \subsubsection{The~instance~`#3'~(template~#2/#4)}
+ \subsubsection*{Attribute~values:}
+ \begingroup
+ \@beginparpenalty\@M
+ \def\InstanceKey##1##2{\>\textbf{##1}\>##2\\}
+ \def\InstanceSemantics{\endtabbing\endgroup
+ \vskip-30pt\vskip0pt
+ \subsubsection*{Layout~description~\&~Comments:}}
+ \tabbing
+ xxxx\=#1\=\kill
+ }
+ { \par \bigskip }
+\DeclareDocumentCommand \OnlyDescription { }
+ { \bool_gset_false:N \g__codedoc_typeset_implementation_bool }
+\DeclareDocumentCommand \AlsoImplementation { }
+ { \bool_gset_true:N \g__codedoc_typeset_implementation_bool }
+\DeclareDocumentCommand \StopEventually { m }
+ {
+ \bool_if:NTF \g__codedoc_typeset_implementation_bool
+ {
+ \@bsphack
+ \tl_gset:Nn \g__codedoc_finale_tl { #1 \check@checksum }
+ \init@checksum
+ \@esphack
+ }
+ { #1 \endinput }
+ }
+\DeclareDocumentCommand \Finale { }
+ { \tl_use:N \g__codedoc_finale_tl }
+\tl_new:N \g__codedoc_finale_tl
+\cs_new_protected:Npn \__codedoc_input:n #1
+ {
+ \tl_gclear:N \g__codedoc_module_name_tl
+ \MakePercentIgnore
+ \input{#1}
+ \MakePercentComment
+ }
+\DeclareDocumentCommand \DocInput { m }
+ {
+ \clist_map_inline:nn {#1}
+ {
+ \clist_put_right:Nn \g_docinput_clist {##1}
+ \__codedoc_input:n {##1}
+ }
+ }
+\DeclareDocumentCommand \DocInputAgain { }
+ { \clist_map_function:NN \g_docinput_clist \__codedoc_input:n }
+\NewDocumentCommand \DocInclude { m }
+ {
+ \relax\clearpage
+ \docincludeaux
+ \IfFileExists{#1.fdd}
+ { \cs_set:Npn \currentfile{#1.fdd} }
+ { \cs_set:Npn \currentfile{#1.dtx} }
+ \int_compare:nNnTF \@auxout = \@partaux
+ { \@latexerr{\string\include\space cannot~be~nested}\@eha }
+ { \@docinclude #1 }
+ }
+\cs_gset:Npn \@docinclude #1
+ {
+ \clearpage
+ \immediate\write\@mainaux{\string\@input{#1.aux}}
+ \@tempswatrue
+ \if@partsw
+ \@tempswafalse
+ \cs_set:Npx \@tempb{#1}
+ \@for\@tempa:=\@partlist\do
+ {
+ \ifx\@tempa\@tempb\@tempswatrue\fi
+ }
+ \fi
+ \if@tempswa
+ \cs_set_eq:NN \@auxout \@partaux
+ \immediate\openout\@partaux #1.aux
+ \immediate\write\@partaux{\relax}
+ \cs_set_eq:NN \@ltxdoc@PrintIndex \PrintIndex
+ \cs_set_eq:NN \PrintIndex \relax
+ \cs_set_eq:NN \@ltxdoc@PrintChanges \PrintChanges
+ \cs_set_eq:NN \PrintChanges \relax
+ \cs_set_eq:NN \@ltxdoc@theglossary \theglossary
+ \cs_set_eq:NN \@ltxdoc@endtheglossary \endtheglossary
+ \part{\currentfile}
+ {
+ \cs_set_eq:NN \ttfamily\relax
+ \cs_gset:Npx \filekey
+ { \filekey, \thepart = { \ttfamily \currentfile } }
+ }
+ \DocInput{\currentfile}
+ \cs_set_eq:NN \PrintIndex \@ltxdoc@PrintIndex
+ \cs_set_eq:NN \PrintChanges \@ltxdoc@PrintChanges
+ \cs_set_eq:NN \theglossary \@ltxdoc@theglossary
+ \cs_set_eq:NN \endtheglossary \@ltxdoc@endtheglossary
+ \clearpage
+ \@writeckpt{#1}
+ \immediate \closeout \@partaux
+ \else
+ \@nameuse{cp@#1}
+ \fi
+ \cs_set_eq:NN \@auxout \@mainaux
+ }
+\cs_gset:Npn \codeline@wrindex #1
+ {
+ \immediate\write\@indexfile
+ {
+ \string\indexentry{#1}
+ { \filesep \int_use:N \c@CodelineNo }
+ }
+ }
+\tl_gclear:N \filesep
+\cs_gset:Npn \docincludeaux
+ {
+ \tl_set:Nn \thepart { \alphalph { part } }
+ \tl_set:Nn \filesep { \thepart - }
+ \cs_set_eq:NN \filekey \use_none:n
+ \tl_gput_right:Nn \index@prologue
+ {
+ \cs_gset:Npn \@oddfoot
+ {
+ \parbox { \textwidth }
+ {
+ \strut \footnotesize
+ \raggedright { \bfseries File~Key: } ~ \filekey
+ }
+ }
+ \cs_set_eq:NN \@evenfoot \@oddfoot
+ }
+ \cs_gset_eq:NN \docincludeaux \relax
+ \cs_gset:Npn \@oddfoot
+ {
+ \cs_if_exist:cTF { ver @ \currentfile }
+ { File~\thepart :~{\ttfamily\currentfile}~ }
+ {
+ \GetFileInfo{\currentfile}
+ File~\thepart :~{\ttfamily\filename}~
+ Date:~\ExplFileDate\ % space
+ Version~\ExplFileVersion
+ }
+ \hfill \thepage
+ }
+ \cs_set_eq:NN \@evenfoot \@oddfoot
+ }
+\group_begin:
+ \char_set_catcode_other:N \^^A
+ \char_set_catcode_active:N \^^S
+ \char_set_catcode_active:N \^^B
+ \char_set_catcode_other:N \^^L
+ \char_set_catcode_other:N \^^R
+ \char_set_lccode:nn { `\^^A } { `\% }
+ \char_set_lccode:nn { `\^^S } { `\ }
+ \char_set_lccode:nn { `\^^B } { `\\ }
+ \char_set_lccode:nn { `\^^L } { `\{ }
+ \char_set_lccode:nn { `\^^R } { `\} }
+ \tex_lowercase:D
+ {
+ \group_end:
+ \cs_set_protected:Npn \xmacro@code
+ #1 ^^A ^^S^^S^^S^^S ^^Bend ^^Lmacrocode^^R
+ { \__codedoc_xmacro_code:n {#1} \end{macrocode} }
+ }
+\group_begin:
+ \char_set_catcode_active:N \<
+ \char_set_catcode_active:N \>
+ \cs_new_protected:Npn \__codedoc_xmacro_code:n #1
+ {
+ \tl_if_in:nnTF {#1} { < @ @ = }
+ { \__codedoc_xmacro_code:w #1 \q_stop }
+ {
+ \tl_set:Nn \l__codedoc_tmpa_tl {#1}
+ \__codedoc_replace_at_at:N \l__codedoc_tmpa_tl
+ \tl_use:N \l__codedoc_tmpa_tl
+ }
+ }
+ \cs_new_protected:Npn \__codedoc_xmacro_code:w #1 < @ @ = #2 > #3 \q_stop
+ {
+ \tl_set:Nn \l__codedoc_tmpa_tl {#1}
+ \__codedoc_replace_at_at:N \l__codedoc_tmpa_tl
+
+ \tl_gset:Nn \g__codedoc_module_name_tl {#2}
+ \tl_put_right:Nn \l__codedoc_tmpa_tl { < @ @ = #2 > }
+
+ \tl_set:Nn \l__codedoc_tmpb_tl {#3}
+ \__codedoc_replace_at_at:N \l__codedoc_tmpb_tl
+ \tl_put_right:No \l__codedoc_tmpa_tl { \l__codedoc_tmpb_tl }
+
+ \tl_use:N \l__codedoc_tmpa_tl
+ }
+\group_end:
+\iow_new:N \g__codedoc_func_iow
+\tl_new:N \l__codedoc_doc_def_tl
+\tl_new:N \l__codedoc_doc_undef_tl
+\tl_new:N \l__codedoc_undoc_def_tl
+\cs_new_protected:Npn \__codedoc_show_functions_defined:
+ {
+ \bool_lazy_and:nnT
+ { \g__codedoc_typeset_implementation_bool } { \g__codedoc_checkfunc_bool }
+ {
+ \iow_term:x { \c__codedoc_iow_separator_tl \iow_newline: }
+ \iow_open:Nn \g__codedoc_func_iow { \c_sys_jobname_str .cmds }
+
+ \tl_clear:N \l__codedoc_doc_def_tl
+ \tl_clear:N \l__codedoc_doc_undef_tl
+ \tl_clear:N \l__codedoc_undoc_def_tl
+ \seq_map_inline:Nn \g_doc_functions_seq
+ {
+ \seq_if_in:NnTF \g_doc_macros_seq {##1}
+ {
+ \tl_put_right:Nx \l__codedoc_doc_def_tl
+ { ##1 \iow_newline: }
+ \iow_now:Nn \g__codedoc_func_iow { > ~ ##1 }
+ }
+ {
+ \tl_put_right:Nx \l__codedoc_doc_undef_tl
+ { ##1 \iow_newline: }
+ \iow_now:Nn \g__codedoc_func_iow { ! ~ ##1 }
+ }
+ }
+ \seq_map_inline:Nn \g_doc_macros_seq
+ {
+ \seq_if_in:NnF \g_doc_functions_seq {##1}
+ {
+ \tl_put_right:Nx \l__codedoc_undoc_def_tl
+ { ##1 \iow_newline: }
+ \iow_now:Nn \g__codedoc_func_iow { ? ~ ##1 }
+ }
+ }
+ \__codedoc_functions_typeout:nN
+ {
+ Functions~both~documented~and~defined: \iow_newline:
+ (In~order~of~being~documented)
+ }
+ \l__codedoc_doc_def_tl
+ \__codedoc_functions_typeout:nN
+ { Functions~documented~but~not~defined: }
+ \l__codedoc_doc_undef_tl
+ \__codedoc_functions_typeout:nN
+ { Functions~defined~but~not~documented: }
+ \l__codedoc_undoc_def_tl
+
+ \iow_close:N \g__codedoc_func_iow
+ \iow_term:x { \c__codedoc_iow_separator_tl }
+ }
+ }
+\AtEndDocument { \__codedoc_show_functions_defined: }
+\cs_new_protected:Npn \__codedoc_functions_typeout:nN #1#2
+ {
+ \tl_if_empty:NF #2
+ {
+ \typeout
+ {
+ \c__codedoc_iow_midrule_tl \iow_newline:
+ #1 \iow_newline:
+ \c__codedoc_iow_midrule_tl \iow_newline:
+ #2
+ }
+ \tl_clear:N #2
+ }
+ }
+\cs_new_protected:Npn \__codedoc_show_not_tested:
+ {
+ \bool_if:NT \g__codedoc_checktest_bool
+ {
+ \tl_clear:N \l__codedoc_tmpa_tl
+ \prop_if_empty:NF \g__codedoc_missing_tests_prop
+ {
+ \cs_set:Npn \__codedoc_tmpa:w ##1##2
+ {
+ \iow_newline:
+ \space\space\space\space \exp_not:n {##1}
+ \clist_map_function:nN {##2} \__codedoc_tmpb:w
+ }
+ \cs_set:Npn \__codedoc_tmpb:w ##1
+ {
+ \iow_newline:
+ \space\space\space\space\space\space * ~ ##1
+ }
+ \tl_put_right:Nx \l__codedoc_tmpa_tl
+ {
+ \iow_newline: \iow_newline:
+ The~ following~ macro(s)~ have~ incomplete~ tests:
+ \iow_newline:
+ \prop_map_function:NN
+ \g__codedoc_missing_tests_prop \__codedoc_tmpa:w
+ }
+ }
+ \seq_if_empty:NF \g__codedoc_not_tested_seq
+ {
+ \cs_set:Npn \__codedoc_tmpa:w ##1
+ { \clist_map_function:nN {##1} \__codedoc_tmpb:w }
+ \cs_set:Npn \__codedoc_tmpb:w ##1
+ {
+ \iow_newline:
+ \space\space\space\space ##1
+ }
+ \tl_put_right:Nx \l__codedoc_tmpa_tl
+ {
+ \iow_newline:
+ \iow_newline:
+ The~ following~ macro(s)~ do~ not~ have~ any~ tests:
+ \iow_newline:
+ \seq_map_function:NN
+ \g__codedoc_not_tested_seq \__codedoc_tmpa:w
+ }
+ }
+ \tl_if_empty:NF \l__codedoc_tmpa_tl
+ {
+ \int_set:Nn \l__codedoc_tmpa_int { \etex_interactionmode:D }
+ \errorstopmode
+ \ClassError { l3doc-TUB } { \l__codedoc_tmpa_tl } { }
+ \int_set:Nn \etex_interactionmode:D { \l__codedoc_tmpa_int }
+ }
+ }
+ }
+\AtEndDocument { \__codedoc_show_not_tested: }
+\g@addto@macro \theindex { \MakePrivateLetters }
+\cs_gset:Npn \verbatimchar {&}
+\setcounter { IndexColumns } { 2 }
+\IndexPrologue
+ {
+ \section*{Index}
+ \markboth{Index}{Index}
+ \addcontentsline{toc}{section}{Index}
+ The~italic~numbers~denote~the~pages~where~the~
+ corresponding~entry~is~described,~
+ numbers~underlined~point~to~the~definition,~
+ all~others~indicate~the~places~where~it~is~used.
+ }
+\cs_gset_protected:Npn \SpecialIndex #1
+ {
+ \@bsphack
+ \__codedoc_special_index:nn {#1} { }
+ \@esphack
+ }
+\msg_new:nnn { l3doc-TUB } { print-index-howto }
+ {
+ Generate~the~index~by~executing\\
+ \iow_indent:n
+ { makeindex~-s~gind.ist~-o~\c_sys_jobname_str.ind~\c_sys_jobname_str.idx }
+ }
+\tl_gput_right:Nn \PrintIndex
+ { \AtEndDocument { \msg_info:nn { l3doc-TUB } { print-index-howto } } }
+\cs_gset_protected:Npn \it@is@a #1
+ {
+ \use:x
+ {
+ \__codedoc_special_index_module:nnnnN
+ {#1}
+ { \bslash #1 }
+ { }
+ { }
+ \c_false_bool
+ }
+ }
+\cs_new_protected:Npn \__codedoc_special_index:nn #1#2
+ {
+ \__codedoc_key_get:n {#1}
+ \quark_if_no_value:NF \l__codedoc_override_module_tl
+ { \tl_set_eq:NN \l__codedoc_index_module_tl \l__codedoc_override_module_tl }
+ \__codedoc_special_index_module:ooonN
+ { \l__codedoc_index_key_tl }
+ { \l__codedoc_index_macro_tl }
+ { \l__codedoc_index_module_tl }
+ {#2}
+ \l__codedoc_index_internal_bool
+ }
+\cs_generate_variant:Nn \__codedoc_special_index:nn { o }
+\tl_new:N \l__codedoc_index_escaped_macro_tl
+\tl_new:N \l__codedoc_index_escaped_key_tl
+\cs_new_protected:Npn \__codedoc_special_index_module:nnnnN #1#2#3#4#5
+ {
+ \use:x
+ {
+ \exp_not:n { \__codedoc_special_index_aux:nnnnnn {#1} {#2} }
+ \tl_if_empty:nTF {#3}
+ { { } { } { } }
+ {
+ \str_if_eq:eeTF {#3} { TeX }
+ {
+ { TeX~and~LaTeX2e }
+ { \string\TeX{}~and~\string\LaTeXe{} }
+ }
+ {
+ {#3}
+ { \string\pkg{#3} }
+ }
+ { \bool_if:NT #5 { ~internal } ~commands: }
+ }
+ }
+ {#4}
+ }
+\cs_generate_variant:Nn \__codedoc_special_index_module:nnnnN { ooo }
+\cs_new_protected:Npn \__codedoc_special_index_aux:nnnnnn #1#2#3#4#5#6
+ {
+ \tl_set:Nn \l__codedoc_index_escaped_key_tl {#1}
+ \__codedoc_quote_special_char:N \l__codedoc_index_escaped_key_tl
+ \__codedoc_special_index_set:Nn \l__codedoc_index_escaped_macro_tl {#2}
+ \str_if_eq:onTF { \@currenvir } { macrocode }
+ { \codeline@wrindex }
+ {
+ \str_case:nnF {#6}
+ {
+ { main } { \codeline@wrindex }
+ { usage } { \index }
+ }
+ { \HD@target \index }
+ }
+ {
+ \tl_if_empty:nF { #3 #4 #5 }
+ { #3 #5 \actualchar #4 #5 \levelchar }
+ \l__codedoc_index_escaped_key_tl
+ \actualchar
+ {
+ \token_to_str:N \verbatim@font \c_space_tl
+ \l__codedoc_index_escaped_macro_tl
+ }
+ \encapchar
+ hdclindex{\the\c@HD@hypercount}{#6}
+ }
+ }
+\cs_new_protected:Npn \__codedoc_special_index_set:Nn #1#2
+ {
+ \tl_set:Nx #1 { \tl_to_str:n {#2} }
+ \__codedoc_if_almost_str:nTF {#2}
+ {
+ \tl_replace_all:Non #1 { \tl_to_str:n { __ } }
+ {
+ \verbatimchar
+ \token_to_str:N \_ \token_to_str:N \_
+ \token_to_str:N \verb * \verbatimchar
+ }
+ \exp_args:Nx \tl_map_inline:nn
+ { \tl_to_str:N \verbatimchar \token_to_str:N _ }
+ {
+ \tl_replace_all:Nnn #1 {##1}
+ {
+ \verbatimchar \c__codedoc_backslash_tl ##1
+ \token_to_str:N \verb * \verbatimchar
+ }
+ }
+ \tl_set:Nx #1
+ {
+ \token_to_str:N \verb * \verbatimchar
+ #1 \verbatimchar
+ }
+ }
+ {
+ \tl_set:Nn #1 {#2}
+ \tl_replace_all:Non #1
+ { \c__codedoc_backslash_tl }
+ { \token_to_str:N \bslash \c_space_tl }
+ }
+ \__codedoc_quote_special_char:N #1
+ }
+\cs_new_protected:Npn \__codedoc_quote_special_char:N #1
+ {
+ \tl_map_inline:nn { \quotechar \actualchar \encapchar \levelchar }
+ {
+ \tl_replace_all:Nxn #1
+ { \tl_to_str:N ##1 } { \quotechar \tl_to_str:N ##1 }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_key_get:n #1
+ {
+ \__codedoc_key_get_base:nN {#1} \l__codedoc_index_macro_tl
+ \tl_set:Nx \l__codedoc_index_key_tl
+ { \tl_to_str:N \l__codedoc_index_macro_tl }
+ \tl_clear:N \l__codedoc_index_module_tl
+ \tl_if_in:NoTF \l__codedoc_index_key_tl { \tl_to_str:n { __ } }
+ { \bool_set_true:N \l__codedoc_index_internal_bool }
+ { \bool_set_false:N \l__codedoc_index_internal_bool }
+ \tl_if_head_eq_charcode:oNT
+ { \l__codedoc_index_key_tl } \c__codedoc_backslash_token
+ { \__codedoc_key_pop: }
+ \tl_if_in:NoTF \l__codedoc_index_key_tl { \token_to_str:N : }
+ { \__codedoc_key_func: }
+ {
+ \tl_if_in:NoTF \l__codedoc_index_key_tl { \token_to_str:N _ }
+ { \__codedoc_key_var: }
+ {
+ \tl_if_in:NoT \l__codedoc_index_key_tl { \token_to_str:N @ }
+ { \tl_set:Nn \l__codedoc_index_module_tl { TeX } }
+ }
+ }
+ }
+\cs_new_protected:Npn \__codedoc_key_pop:
+ {
+ \tl_set:Nx \l__codedoc_index_key_tl
+ { \tl_tail:N \l__codedoc_index_key_tl }
+ }
+\cs_new_protected:Npn \__codedoc_key_trim_module:n #1
+ {
+ \cs_set:Npn \__codedoc_tmpa:w ##1 #1 ##2 \q_stop
+ { \exp_not:n {##1} }
+ \tl_set:Nx \l__codedoc_index_module_tl
+ { \exp_after:wN \__codedoc_tmpa:w \l__codedoc_index_module_tl #1 \q_stop }
+ }
+\cs_new_protected:Npn \__codedoc_key_drop_underscores:
+ {
+ \tl_if_head_eq_charcode:oNT { \l__codedoc_index_key_tl } _
+ { \__codedoc_key_pop: \__codedoc_key_drop_underscores: }
+ }
+\cs_new_protected:Npn \__codedoc_key_func:
+ {
+ \tl_if_head_eq_charcode:oNT { \l__codedoc_index_key_tl } .
+ { \__codedoc_key_pop: }
+ \__codedoc_key_drop_underscores:
+ \tl_set_eq:NN \l__codedoc_index_module_tl \l__codedoc_index_key_tl
+ \exp_args:No \__codedoc_key_trim_module:n { \token_to_str:N : }
+ \exp_args:No \__codedoc_key_trim_module:n { \token_to_str:N _ }
+ }
+\cs_new_protected:Npn \__codedoc_key_var:
+ {
+ \exp_args:Nx \tl_if_head_eq_charcode:nNTF
+ { \exp_args:No \str_tail:n \l__codedoc_index_key_tl } _
+ {
+ \str_case:fn { \str_head:N \l__codedoc_index_key_tl }
+ {
+ { q } { \tl_set:Nn \l__codedoc_index_module_tl { quark } }
+ { s } { \tl_set:Nn \l__codedoc_index_module_tl { quark } }
+ }
+ \__codedoc_key_pop:
+ \__codedoc_key_pop:
+ \__codedoc_key_drop_underscores:
+ \tl_if_empty:NT \l__codedoc_index_module_tl
+ {
+ \seq_set_split:NoV \l__codedoc_tmpa_seq
+ { \token_to_str:N _ } \l__codedoc_index_key_tl
+ \tl_set:Nx \l__codedoc_index_module_tl
+ {
+ \int_case:nnF { \seq_count:N \l__codedoc_tmpa_seq }
+ {
+ { 0 } { }
+ { 1 } { int }
+ { 2 } { \seq_item:Nn \l__codedoc_tmpa_seq { 2 } }
+ }
+ { \seq_item:Nn \l__codedoc_tmpa_seq { 1 } }
+ }
+ }
+ }
+ {
+ \tl_set_eq:NN \l__codedoc_index_module_tl \l__codedoc_index_key_tl
+ \exp_args:No \__codedoc_key_trim_module:n { \token_to_str:N _ }
+ }
+ }
+\GlossaryPrologue
+ {
+ \part*{Change~History}
+ {\GlossaryParms\ttfamily\hyphenchar\font=`\-}
+ \markboth{Change~History}{Change~History}
+ \addcontentsline{toc}{part}{Change~History}
+ }
+\msg_new:nnn { l3doc-TUB } { print-changes-howto }
+ {
+ Generate~the~change~list~by~executing\\
+ \iow_indent:n
+ { makeindex~-s~gglo.ist~-o~\c_sys_jobname_str.gls~\c_sys_jobname_str.glo }
+ }
+\tl_gput_right:Nn \PrintChanges
+ { \AtEndDocument { \msg_info:nn { l3doc-TUB } { print-changes-howto } } }
+\bool_if:NTF \g__codedoc_typeset_implementation_bool
+ {
+ \RecordChanges
+ \CodelineIndex
+ \EnableCrossrefs
+ \AlsoImplementation
+ }
+ {
+ \CodelineNumbered
+ \DisableCrossrefs
+ \OnlyDescription
+ }
+
+%%FMi
+
+\def\maketitle{\@ifstar
+ {\@articletitlefalse\@r@maketitle}%
+ {\@articletitletrue\@r@maketitle}%
+}
+
+%%
+%%
+%% End of file `l3doc-TUB.cls'.
diff --git a/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-code.pdf b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-code.pdf
new file mode 100644
index 00000000000..17a9c6bc61c
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-code.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-code.tex b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-code.tex
new file mode 100644
index 00000000000..7f9a4882199
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-code.tex
@@ -0,0 +1,4 @@
+% this will typeset documentation + code
+
+\AtBeginDocument{\AlsoImplementation}
+\input{unicodefonttable.dtx}
diff --git a/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-doc.pdf b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-doc.pdf
new file mode 100644
index 00000000000..87914ad4965
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-doc.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-doc.tex b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-doc.tex
new file mode 100644
index 00000000000..4b98461ade3
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-doc.tex
@@ -0,0 +1,6 @@
+% this will typeset only documentation but not the code
+
+\AtBeginDocument{\OnlyDescription
+% \let\tableofcontents\relax
+ }
+\input{unicodefonttable.dtx}
diff --git a/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-samples.pdf b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-samples.pdf
new file mode 100644
index 00000000000..b5a4d6399a7
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-samples.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-samples.tex b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-samples.tex
new file mode 100644
index 00000000000..3a14c32014a
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/unicodefonttable/unicodefonttable-samples.tex
@@ -0,0 +1,104 @@
+%%
+%% This is file `unicodefonttable-samples.tex',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% unicodefonttable.dtx (with options: `samples')
+%%
+%% This is a generated file.
+%%
+%% Copyright 2019-2021 Frank Mittelbach
+%%
+%% This file was generated from file(s) of the LaTeX `unicodefonttable Bundle'.
+%% --------------------------------------------------------------------------
+%%
+%% It may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either version 1.3c
+%% of this license or (at your option) any later version.
+%% The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt
+%% and version 1.3c or later is part of all distributions of LaTeX
+%% version 2008 or later.
+%%
+%% This file may only be distributed together with a copy of the LaTeX
+%% `unicodefonttable Bundle'. You may however distribute the `unicodefonttable Bundle'
+%% without such generated files.
+%%
+%% The newest sources can be found below
+%%
+%% https://github.com/FrankMittelbach/fmitex-unicodetable
+%%
+%% where one can also log issues in case there are any.
+%%
+%%
+%%%%% \iffalse meta-comment
+%% File: unicodefonttable.dtx (C) Copyright 2019-2021 Frank Mittelbach
+
+\def\unicodefonttabledate {2021/10/19}
+\def\unicodefonttableversion{v1.0e}
+
+
+%!TEX program = lualatex
+
+\documentclass{article}
+
+\usepackage{xparse,color}
+
+\usepackage{fontspec}
+
+\setmainfont{Linux Biolinum O}
+\setmonofont{SourceCodePro}
+
+\usepackage{unicodefonttable}
+
+\addtolength\textwidth{30pt}
+
+\begin{document}
+
+\listoftables
+
+\section{Computer Modern --- 8bit font}
+
+\displayfonttable*[color=none,
+ range-end = 7F,
+]{cmr10}
+
+
+\newpage
+
+\section{TeX Gyre Heros (Helvetica) --- 8bit font}
+
+\displayfonttable*[color=red,nostatistics=false,
+ hex-digits = head+foot,
+ range-end = FF,
+]{ec-qhvr}
+
+\newpage
+
+\section{Latin Modern Sans --- OTF font}
+
+\displayfonttable[
+ % missing-glyph = \tiny\setlength\fboxsep{0pt}\fbox{$\times$},
+ hex-digits = block,
+ title-cont-format = \caption[]{\emph{continued}},
+]{Latin Modern Sans}
+
+\newpage
+
+\section{\TeX{} Gyre Pagella (Palatino) oldstyle figures --- OTF font}
+
+\displayfonttable{TeX Gyre Pagella}[Numbers=OldStyle]
+
+\newpage
+
+\section{Comparing Latin Modern Math with New Computer Modern Math}
+
+\displayfonttable[compare-with=NewCMMath-Regular.otf, range-end=1FFFF]
+ {latinmodern-math.otf}
+
+\end{document}
+
+\endinput
+%%
+%% End of file `unicodefonttable-samples.tex'.
diff --git a/Master/texmf-dist/source/latex/unicodefonttable/unicodefonttable.dtx b/Master/texmf-dist/source/latex/unicodefonttable/unicodefonttable.dtx
new file mode 100644
index 00000000000..67cb3a8d643
--- /dev/null
+++ b/Master/texmf-dist/source/latex/unicodefonttable/unicodefonttable.dtx
@@ -0,0 +1,2295 @@
+%%%%% \iffalse meta-comment
+%
+%% File: unicodefonttable.dtx (C) Copyright 2019-2021 Frank Mittelbach
+%
+% 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
+%
+% https://www.latex-project.org/lppl.txt
+%
+%
+% The development version of the bundle can be found below
+%
+% https://github.com/FrankMittelbach/fmitex/
+%
+% for those people who are interested or want to report an issue.
+%
+
+\def\unicodefonttabledate {2021/10/19}
+\def\unicodefonttableversion{v1.0e}
+
+
+%<*driver>
+\documentclass{l3doc-TUB}
+
+% some fixes local to this documentation
+
+\ExplSyntaxOn
+ \cs_new:Npn\IfImplementationShownTF
+ {\bool_if:NTF \g__codedoc_typeset_implementation_bool}
+\ExplSyntaxOff
+
+\makeatletter
+\def\meta@font@select{\normalfont\itshape}
+
+\IndexPrologue{%
+ \IfImplementationShownTF{\section*{Index}%
+ Numbers written in italic refer to the page
+ where the corresponding entry is described
+ or mentioned. Numbers underlined refer to the
+ code line of the
+ definition; numbers in Roman refer to the
+ code lines where the entry is used.}%
+ {\section{Index}%
+ Numbers written in italic refer to the page
+ where the corresponding entry is described
+ or mentioned.}}
+
+\makeatother
+
+
+\usepackage{graphicx,unicodefonttable}
+
+\EnableCrossrefs
+\CodelineIndex
+\begin{document}
+ \DocInput{unicodefonttable.dtx}
+\advance\signaturewidth by 40pt
+\makesignature
+\end{document}
+%</driver>
+%
+% \fi
+%
+% \tracinglostchars=3
+%
+% \newcommand\key [1]{\texttt{#1}}
+% \newcommand\kval[1]{\texttt{#1}}
+%
+% \newcommand\keysetup[1]{\noindent\marginpar{\raggedleft Key setup: #1}\ignorespaces}
+% \renewcommand\keysetup[1]{\paragraph*{\hspace*{-8pc}Key setup (#1)}}
+%
+%
+% \title{The \texttt{unicodefonttable} package\thanks{This is
+% version \unicodefonttableversion\ of the package, dated
+% \unicodefonttabledate; the license is LPPL.}}
+% \author{Frank Mittelbach}
+% \address{Mainz, Germany}
+% \netaddress{https://www.latex-project.org}
+% \personalURL{https://ctan.org/pkg/unicodefonttable}
+% \raggedbottom
+%
+% \maketitle
+%
+%
+% \begin{abstract}
+% A package for typesetting font tables for larger fonts, e.g.,
+% TrueType or OpenType Unicode fonts.
+% To produce a one-off table, a standalone version is available as well.
+% \end{abstract}
+%
+%
+% \tableofcontents
+%
+%
+%
+% \section{Introduction}
+%
+% When I started to write a new chapter for the third edition of
+% \emph{The \LaTeX{} Companion} on modern fonts available for
+% different \LaTeX{} engines, I was a bit surprised that I couldn't
+% find a way to easily typeset tables showing the glyphs available in
+% TrueType or OpenType fonts. The \pkg{nfssfont} package available
+% with \LaTeX{} only supports fonts from the 8-bit world, but
+% modern fonts that can be used with \XeTeX{} or \LuaTeX{} can
+% contain thousands of glyphs and having a method to display what
+% is available in them was important for me.
+%
+% I therefore set out to write my own little package and what
+% started as an afternoon exercise ended up being this package,
+% offering plenty of bells and whistles for typesetting such
+% font tables.
+%
+% As there can be many glyphs in such fonts a tabular
+% representation of them might run for several pages, so the
+% package internally uses the \pkg{longtable} package to handle
+% that.
+%
+% In most cases the glyphs inside the fonts are indexed by their
+% Unicode numbers so it is natural to display them sorted by their
+% position in the Unicode character set.
+%
+% Unicode is organized in named blocks such as ``Basic Latin'',
+% ``Latin-1~Supplement'', etc., typically consisting of 265
+% characters each.\footnote{Some blocks are smaller, while those
+% containing the Asian ideographs are much larger.} It is therefore
+% helpful to use these block names as subtitles within the table,
+% to more easily find the information one is looking for.
+%
+% A common way to represent the number of a single Unicode
+% character is \texttt{U+} followed by four (or more)
+% hexadecimal digits. For example, \texttt{U+0041} represents the letter
+% ``A'' and \texttt{U+20AC} the Euro currency symbol ``\texteuro''.
+% We use this convention by showing a Unicode range of sixteen
+% characters at the left of each table row, e.g., \texttt{U+0040 -
+% 004F}, followed by the sixteen glyphs in the range. Thus that
+% particular table row from the ``Basic Latin'' block would show
+% something like
+%
+% \displayfonttable*[noheader,range-start=0040, range-end=004F,
+% color=black!50]{Latin Modern Sans}
+%
+% If a Unicode character has no glyph representation in a given
+% font then this is indicated by a special symbol (by default a
+% colored hyphen). By default some color is used, but we've grayscaled
+% the output for \TUB.
+%
+% In order to easily locate any Unicode character the table shows by
+% default sixteen hex digits as a column heading. For example, to find
+% Euro currency symbol (\texttt{U+20AC}) one first finds the
+% right row, which is the range \texttt{U+20A0 - 20AF}, and then
+% the \texttt{C} column in that row, and the glyph is there (or an
+% indication that the font is missing that glyph;
+% the line shows that for some of the other slots).
+%
+% \displayfonttable*[noheader,range-start=20A0, range-end=20AF,
+% color=black!50]{Latin Modern Sans}
+%
+% It can be useful to compare two fonts with each other by
+% filling the table with glyphs from a secondary font if the
+% primary font is missing them. For example, the next display shows
+% two rows of Latin Modern Math (black glyphs) and instead of showing
+% a missing glyph symbol in most slots, we use the glyphs from New
+% Computer Modern Math, which has a much larger glyph set
+% (normally red glyphs with gray background but again, grayscaled for
+% \TUB).
+%
+%
+% \displayfonttable[noheader,nostatistics,display-block=none,
+% compare-with=NewCMMath-Regular.otf,range-start=2A00,range-end=2A1F,
+% color=black!50,compare-color=none]
+% {latinmodern-math.otf}
+%
+%
+% \section{The user interface}
+%
+% The package offers one command to typeset a font table. The
+% appearance of the table can be customized by specifying key/value
+% pairs.
+%
+% \begin{function}{\displayfonttable}
+% \begin{syntax}
+% \cs{displayfonttable} \texttt{*} \oarg{key/value-list} \Arg{font-name} \oarg{font-features}
+% \end{syntax}
+% The \meta{font-name} is the font to be displayed. This and the
+% \meta{font-features} argument are passed to \pkg{fontspec}, thus they
+% should follow the conventions of that package for specifying a
+% font. The \meta{key/value-list} offers customization
+% possibilities discussed below.
+%
+% The \cs{displayfonttable*} is a variant of the command, intended
+% for use with 8-bit legacy fonts. It presets some keys, but
+% otherwise behaves identically. The preset values are:
+%\begin{verbatim}
+% nostatistics, display-block=none, hex-digits=head, range-end=FF
+%\end{verbatim}
+% For details see the next section.
+% \end{function}
+%
+%
+%
+% \begin{function}{\fonttablesetup}
+% \begin{syntax}
+% \cs{fonttablesetup} \Arg{key/value-list}
+% \end{syntax}
+% Instead of or in addition to specifying key/values to
+% \cs{displayfonttable} it is possible to set them up as
+% defaults. Inside \cs{displayfonttable} the defaults are applied first,
+% so one can still overwrite their values for an individual table.
+% \end{function}
+%
+%
+% \begin{function}{\fonttableglyphcount}
+% \begin{syntax}
+% \cs{fonttableglyphcount}
+% \end{syntax}
+% While typesetting a font table the package keeps track of the
+% number of glyphs it finds in the font. After the table has finished,
+% this value is available in \cs{fonttableglyphcount} and it is, for
+% example, used when statistics are produced. At the start of the
+% next table it is reset to zero.
+% \end{function}
+%
+%
+%
+%
+% \subsection{Keys and their values}
+%
+% Several of the available keys are booleans accepting \texttt{true}
+% or \texttt{false}. They usually exist in pairs so that one can
+% specify the desired behavior without needing to provide a value,
+% e.g., specifying \key{header} is equivalent to specifying
+% \key{header}\texttt{=true} or \key{noheader}\texttt{=false}, etc.
+% In the lists below the default settings are indicated by an
+% underline.
+%
+% \begin{variable}{
+% header, noheader,
+% title-format, title-format-cont,
+% }
+% The first set of keys is concerned with the overall look and
+% feel of the generated table.
+% \begin{description}
+% \item[\underline{\key{header}}, \key{noheader}]
+% These keys determine whether a header to the table is
+% produced.
+%
+% \item[\key{title-format}, \key{title-format-cont}]
+% These keys define what is provided as a header title or
+% continuation title if the table consists of several pages.
+% They expect code as their value. This code can contain \verb=#1=
+% and \verb=#2= to denote the \meta{font-name} and
+% \meta{font-features} arguments, respectively.
+%
+% By default a title using the \cs{caption} command is produced; on
+% continuation titles, the \meta{font-features} are not shown.
+% This is typeset as a \env{longtable} header row, so you either need to use
+% \cs{multicolumn} or a \cs{caption} command\Dash otherwise everything
+% ends up in the first column.
+%
+% \end{description}
+%
+% \end{variable}
+%
+%
+% \begin{variable}{
+% display-block,
+% hex-digits, color,
+% }
+% These keys handle the inner parts of the table.
+%
+% \begin{description}
+% \item[\key{display-block}]
+% The Unicode dataset is organized in named blocks that are typically 128 or
+% 256 characters, though some are noticeably larger and a few are
+% smaller. With the \key{display-block} key it is
+% possible to specify if and how such blocks should be made visible.
+% The following values are supported:
+% \begin{description}
+% \item[\underline{\kval{titles}}]
+% Above each display block that contains glyphs the Unicode title
+% of the block is displayed.
+%
+% \item[\kval{rules}]
+% Display blocks are indicated only by a \cs{midrule}.
+%
+% \item[\kval{none}]
+% Display blocks are not indicated at all.
+% \end{description}
+%
+% \item[\key{hex-digits}]
+% To ease reading the table, rows of hex digits are added to
+% it. Where or if this happens is controlled by this key. Allowed
+% values for it are the following:
+% \begin{description}
+% \item[\kval{block}]
+% A row of hex digits is placed at the beginning of each Unicode
+% block containing glyphs in the displayed font.
+%
+% \item[\kval{foot}]
+% A row is added to the foot of each table page.
+%
+% \item[\underline{\kval{head}}]
+% A row is added to the top of each table page.
+%
+% \item[\kval{head+foot}]
+% A row is added to the top and the foot of each table page.
+%
+% \item[\kval{none}]
+% All hex digit rows are suppressed.
+% \end{description}%
+%
+% \item[\key{hex-digits-font}]
+% The font to use for the hex digits, by default
+% \underline{\cs{ttfamily}\cs{scriptsize}}.{\hfuzz=2.7pt\par}
+%
+% \item[\key{color}]
+% This key determines the color for parts of the table (hex digits
+% and Unicode ranges). It can be either \kval{none} or a color
+% specification as understood by the \cs{color} command.
+% The default is \underline{\texttt{blue}}.
+%
+% \end{description}
+%
+% \end{variable}
+%
+%
+% \begin{variable}{
+% statistics, nostatistics,
+% statistics-font,statistics-format,
+% }
+% The next set of keys allows altering the statistics that are produced.
+% \begin{description}
+%
+% \item[\underline{\key{statistics}}, \key{nostatistics}]
+% These keys determine whether some statistics are listed at
+% the end of the table.
+%
+% \item[\key{statistics-font}]
+% The font used to typeset the statistics; the default is\\
+% \underline{\cs{normalfont}\cs{small}}.
+%
+%
+% \item[\key{statistics-format}]
+% Code (text) to specify what should be typeset in the
+% statistics. One can use \verb=#1= for the \meta{font-name} and
+% \verb=#2= for the glyph count.
+% The material is typeset on a single line at the end of the
+% table. If several lines are needed you need to use \cs{parbox}
+% or a similar construct.
+% \end{description}
+% \end{variable}
+%
+%
+%
+% \begin{variable}{
+% glyph-width,
+% missing-glyph, missing-glyph-font, missing-glyph-color,
+% }
+% Another set of keys deals with customization on the glyph level.
+% \begin{description}
+% \item[\key{glyph-width}]
+% All glyphs are typeset in a box with the same width, the default
+% value is \underline{\texttt{6pt}} which is suitable for most 10pt
+% fonts
+% and make the table fit comfortably into the text width of
+% a typical document.
+%
+% \item[\key{missing-glyph}]
+% If a slot in a row doesn't have a glyph in the font you may still
+% want display something to indicate this state. By giving the key
+% a value any arbitrary glyph or material can be typeset. The
+% default is to typeset a \kval{-} (hyphen) in a special color.
+%
+% Rows that contain no glyph whatsoever are not displayed at
+% all. Instead a small vertical space is added to indicate the one
+% or more rows are omitted.
+%
+% \item[\key{missing-glyph-font}]
+%
+% The font used for the missing glyphs (the default value is
+% \underline{\cs{ttfamily}\cs{scriptsize}}).
+%
+% \item[\key{missing-glyph-color}]
+% If not specified it uses the value specified with the \key{color}
+% key. If you want a different color, e.g., \texttt{red}, you can
+% use a color value or you can specify \kval{none} to use no coloring.
+%
+% \end{description}
+%
+% \end{variable}
+%
+%
+% \begin{variable}{
+% compare-with,compare-color, compare-bgcolor,statistics-compare-format
+% }
+%
+% You can make comparisons between two fonts, which is useful, for
+% example when dealing with incomplete math fonts and you need to
+% see how well the symbols from one font blend with the supplementary
+% symbols from another font.
+%
+% \begin{description}
+% \item[\key{compare-with}]
+%
+% If given, the value is a \meta{comparison-font-name} that is used
+% to supply missing glyphs. This means that if the \meta{font-name}
+% to be displayed is missing a glyph in a slot, then the
+% \meta{comparison-font-name} is checked, and if that font has the
+% glyph in question, it will be displayed instead of showing a
+% missing glyph indicator.
+%
+% \item[\key{compare-color}, \key{compare-bgcolor}]
+%
+% To distinguish real glyphs from missing but substituted glyphs,
+% they can be colored specially (default \underline{\texttt{red}})
+% and/or you can have their background colored (default is
+% \underline{\texttt{black!10}}, i.e., a light gray).
+%
+% \item[\key{statistics-compare-format}]
+%
+% Code (text) to specify what should be typeset in the statistics
+% when comparing two fonts. One can use \verb=#1= for the
+% \meta{font-name} and \verb=#2= for its glyph count, \verb=#3= is
+% the name of the comparison font, \verb=#4= its glyph count,
+% \verb=#5= for the number of glyphs missing in this font and
+% \verb=#6= the number of extra glyphs in it. This code is used
+% instead of \key{statistics-format} when comparisons are made.
+%
+% The material is typeset on a single line at the end of the
+% table. If several lines are needed you need to use \cs{parbox}
+% or a similar construct.
+%
+% \end{description}
+% \end{variable}
+%
+%
+% \begin{variable}{
+% range-start, range-end,
+% }
+% Finally there are two keys for restricting the display range.
+% \begin{description}
+% \item[\key{range-start}, \key{range-end}]
+% The full Unicode set of characters is huge and checking every
+% slot to see if the current font contains a glyph in the slot
+% takes a long time. If you know that font contains only a
+% certain subset then you can speed up the table generation
+% considerably by limiting the search (and consequently the output
+% generation).
+% The \key{range-start} specifies where to start with the search
+% (default \underline{\texttt{0000}}) and \key{range-end} gives
+% the last slot that is tested (default
+% \underline{\texttt{FFFF}}).
+%
+% Thus, by default we restrict the display to slots below
+% \texttt{10000}, because text fonts seldom contain glyphs in the
+% higher planes. But if you want to see everything of the font (as
+% far as supported by this package) and are prepared to wait for
+% the higher
+% planes to be scanned, you can go up to a value of \texttt{FFFFF}.
+%
+% These keys are also quite useful in combination with the previous
+% \key{compare-with} key, to display only, for example, the Greek
+% letters and see how glyphs from two fonts blend with each other.
+
+% \end{description}
+% \end{variable}
+%
+%
+%
+% \subsection{A standalone interactive version}
+%
+% If you want to quickly display a single font, you can run
+% \texttt{unicodefont.tex} through \LuaTeX{} (or \XeTeX{}). Similar to
+% \texttt{nfssfont.tex} (which is for 8-bit fonts with \pdfTeX) it
+% asks you a few questions and then generates the font table for
+% you. There are fewer configuration options available,
+% but this workflow saves you writing a document to get a
+% one-off table.
+%
+% Most font tables need several runs due to the use of
+% \pkg{longtable}, which has to find the right width for the columns
+% across several pages. The \texttt{unicodefont} file therefore
+% remembers your selection from the previous run and asks you if
+% you want to reapply it to speed up the process.
+%
+%
+%
+% \section{Notes on the table data}
+%
+% If you look at some parts of a Unicode font table you see a number of slots that
+% do not show a \enquote{missing glyph} sign, but nonetheless appear
+% to be empty. For example:
+%
+% \displayfonttable[noheader,nostatistics,display-block=none,
+% range-start=0020,range-end=00BF,
+% color=black!50]
+% {TeX Gyre Pagella}
+%
+%
+% The reason is that Unicode contains a lot of special
+% spaces or otherwise invisible characters, e.g., \texttt{U+0020}
+% is the normal space, \texttt{U+00A0} is a non-breaking space,
+% \texttt{U+00AD} is a soft-hyphen (what \LaTeX{} users would
+% indicate with \cs{-}), and so forth. Especially the row
+% \texttt{U+2000-200F} in Table~1 looks strange as it appears to be totally
+% empty, but in fact most of its slots contain spaces of different
+% width.
+%
+%\displayfonttable[noheader,nostatistics,hex-digits=foot,
+% range-start=2000,range-end=202F,
+% color=black!50]
+% {latinmodern-math.otf}
+%
+%
+% Another somewhat surprising area is the \enquote{Mathematical
+% Alphanumeric Symbols} block in math fonts, starting at \texttt{U+1D400}.
+% There you see a number of missing characters, the first two being
+% \texttt{U+1D455} (math italic small h) and \texttt{U+1D49D} (math
+% script B).
+%
+% \displayfonttable[noheader,nostatistics,hex-digits=foot,
+% range-start=1D400,range-end=1D4AF,
+% color=black!50]
+% {latinmodern-math.otf}
+%
+% In this case the reason is \emph{not} that the font
+% fails to implement the characters, but that these characters have
+% already been defined in earlier revisions of the Unicode standard in the
+% lower Unicode plane. For example, the \enquote{h} is the
+% Planck constant \texttt{U+210E} and \texttt{U+212C} is
+% the script capital B, etc. The Unicode Consortium decided not
+% to encode the \emph{same} character twice, hence the apparent
+% holes.
+%
+%
+% \IfImplementationShownTF{}
+% {\appendix
+% \def\theHsection{Appendix.\thesection}
+% \addtocontents{toc}{\smallskip}
+% \setlength\IndexMin{200pt}
+% \PrintIndex
+% }
+%
+%
+% \section{Examples}
+%
+% In this section we show the results of a few calls to
+% \cs{displayfonttable}.
+% The tables are a bit easier to navigate if they use color in some
+% places, but for \TUB{} this is not practical, so we
+% use black and gray.
+%
+% \subsection{Computer Modern Sans --- 8-bit font}
+%
+% Our first example is an 8-bit font which gives a concise table.
+% Command used: \begin{verbatim}
+% \displayfonttable*[color=none, range-end=7F]{cmss10}
+% \end{verbatim}
+%
+% \displayfonttable*[color=none, range-end=7F]{cmss10}
+%
+%
+% \iffalse
+%
+%\subsection{\TeX{} Gyre Pagella (Palatino) oldstyle figures --- OTF font}
+%
+% This example shows Pagella with oldstyle numerals.
+% Command used:
+%\begin{verbatim}
+%\displayfonttable{TeX Gyre Pagella}[Numbers=OldStyle]
+%\end{verbatim}
+%
+%\displayfonttable{TeX Gyre Pagella}[Numbers=OldStyle]
+%
+% \fi
+%
+%
+%
+% \subsection{Latin Modern Math compared to New Computer Modern Math}
+%
+% This example shows the extra symbols available in New Computer
+% Modern Math in comparison to Latin Modern Math as the base font.
+% We use the following setup (including settings for the
+% grayscaled \TUB\ output, as an example of color overrides):
+%\begin{verbatim}
+% \displayfonttable[hex-digits=head+foot, range-end=1FFFF,
+% compare-with=New Computer Modern Math,
+% compare-color=black, compare-bgcolor=black!5,
+% missing-glyph-color=black!50, color=black!75]
+% {Latin Modern Math}
+%\end{verbatim}
+% That is, glyphs only in \texttt{NewCM} are shown with a light gray
+% background.
+%
+% We also extended the range to cover \texttt{U+10000} to
+% \texttt{U+1FFFF} in order to include the Unicode Math alphabets.
+%
+% \displayfonttable[hex-digits=head+foot, range-end=1FFFF,
+% compare-with=New Computer Modern Math,
+% compare-color=black, compare-bgcolor=black!5,
+% missing-glyph-color=black!50, color=black!75]
+% {Latin Modern Math}
+%
+%
+%\subsection{Garamond Libre's Byzantine Musical Symbols}
+%
+% As a final example we exhibit the Byzantine Musical Symbols as provided by
+% Garamond Libre.
+% Command used:
+%\begin{verbatim}
+% \displayfonttable[range-start=1D000, range-end=1D0FF,
+% hex-digits=block,
+% missing-glyph-color=black!50, color=black!75,
+% statistics-format=Total number of glyphs in
+% this block of #1 is #2]
+% {Garamond Libre}
+%\end{verbatim}
+%
+% Note that we have altered the text produced by the statistics,
+% because the default is somewhat misleading if only a portion of
+% the font is displayed. This produces the following table:
+%
+% \displayfonttable[range-start=1D000, range-end=1D0FF,
+% hex-digits=foot,
+% missing-glyph-color=black!50, color=black!75,
+% statistics-format=Total number of glyphs in
+% this block of #1 is #2]
+% {Garamond Libre}
+%
+%
+%
+% \IfImplementationShownTF
+% {\StopEventually{\setlength\IndexMin{200pt} \PrintIndex }}
+% {\StopEventually{}}
+%
+%
+%
+% \section{The package implementation}
+%
+% \hfuzz=10pt ^^A lots of slightly overfull tt lines
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% By default the package uses coloring to improve the table
+% appearance and therefore requires a color package.
+% \begin{macrocode}
+\RequirePackage{xcolor}
+% \end{macrocode}
+%
+
+% \begin{macrocode}
+%<@@=fmuft>
+% \end{macrocode}
+%
+% We need the package \pkg{xparse} for specifying the document-level
+% interface commands and \pkg{l3keys2e} to use the \pkg{expl3} key
+% value methods within \LaTeXe{}. These packages automatically
+% require \pkg{expl3} so there is no need to load that explicitly.
+% Actually, \pkg{expl3}, \pkg{l3keys2e} and the \pkg{xparse}
+% functionality is now all part of the \LaTeX{} kernel so the next
+% line is actually not needed at all with a current \LaTeX{} kernel, but
+% in order to support older installations we keep it for now.
+%
+% \begin{macrocode}
+\RequirePackage{xparse,l3keys2e}
+% \end{macrocode}
+%
+% Here we introduce the package and specify its version number:
+% \begin{macrocode}
+\ProvidesExplPackage{unicodefonttable}
+ {\unicodefonttabledate}
+ {\unicodefonttableversion}
+ {Producing font tables for Unicode and other fonts}
+% \end{macrocode}
+%
+% \newcommand\hex[1]{$\langle\textit{hex}_{#1}\rangle$}
+%
+%
+%
+%
+%
+% \subsection{User interface commands}
+%
+%
+% Throughout the implementation we will define a number of keys (and
+% their allowed values). We introduce them at the point where they are
+% used, so they are sprinkled throughout the code.\footnote{This fits
+% with the way this package was developed. I first implemented a
+% single rigid table layout without configuration possibilities and
+% then thought about which parts I wanted to have flexible. I then
+% replaced the rigid code with code that is affected by setting
+% key/value pairs.}
+
+% \begin{macro}{\fonttablesetup}
+% To set up user defaults for the keys we provide a standard
+% interface. The command \cs{unicodefonttabletablesetup} expects a
+% key/value list and can be called as often as necessary.
+% \begin{macrocode}
+\NewDocumentCommand \fonttablesetup { m }
+ { \keys_set:nn {@@} {#1} \ignorespaces }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\displayfonttable}
+% The document-level command for generating a font table.
+% \begin{macrocode}
+\NewDocumentCommand\displayfonttable {s O{} m o}{%
+ \IfBooleanTF #1
+ {
+% \end{macrocode}
+% For the starred form we preset a number of keys with values
+% suitable when displaying 8-bit legacy fonts.
+% With such fonts Unicode block headers make little
+% sense (as the fonts do not conform to the Unicode layout and
+% since they have at most 265 glyphs). It is therefore also unnecessary to
+% loop over the whole Unicode range of the first plane.
+% If necessary all of them can still be overwritten in the optional argument.
+% \begin{macrocode}
+ \@@_display_fonttable:nnn
+ {nostatistics,display-block=none,hex-digits=head,range-end=FF,#2}
+ {#3}{#4}
+ }
+ {
+ \@@_display_fonttable:nnn {#2}{#3}{#4}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_display_fonttable:nnn}
+% This command is the main workhorse of the
+% package. It produces a \texttt{longtable} containing all font
+% glyphs with 16 glyphs per row. The first optional argument is
+% used to configure the table through key/value pairs, the
+% mandatory argument is the font name to display (in
+% \texttt{fontspec} conventions) and the final optional argument is
+% the font feature list if any. If the latter is not provided it
+% will get a special value (\texttt{--NoValue--}) assigned by
+% \texttt{xparse}, which is something that can be tested for.
+% \begin{macrocode}
+\cs_new:Npn \@@_display_fonttable:nnn #1#2#3 {
+ \group_begin:
+% \end{macrocode}
+% First initialize the font that should be displayed (perhaps with a
+% feature list) and then update the key/value list using \verb=#1=.
+% \begin{macrocode}
+ \fontspec{#2}[#3]
+ \keys_set:nn{@@}{#1}
+% \end{macrocode}
+% If the user has asked for a comparsion to some other font we need to set this up:
+% \begin{macrocode}
+ \tl_if_empty:NTF \l_@@_compare_with_tl
+ { \tl_clear:N \l_@@_compare_font_tl }
+ {
+ \setfontface \l_@@_compare_font_tl {\l_@@_compare_with_tl}[]
+ \cs_set_eq:NN \@@_handle_missing_glyph:n
+ \@@_handle_missing_glyph_compare:n
+ }
+% \end{macrocode}
+% Then we start the table with 17 columns. We use \texttt{longtable}
+% if we produce a caption and \texttt{longtable*} if not (so that
+% the table number is not increased, which would look odd if you
+% have other tables in your document).
+% \begin{macrocode}
+ \begin{longtable\bool_if:NF\l_@@_display_header_bool{*}}
+ {@{}r@{\quad}*{16}{c}@{}}
+% \end{macrocode}
+% Special headers and footers are set up first:
+% \begin{macrocode}
+ \@@_setup_header_footer:nn{#2}{#3}
+% \end{macrocode}
+% Then we produce all table rows with the glyphs.
+% \begin{macrocode}
+ \@@_produce_table_rows:
+% \end{macrocode}
+% At the very end we may typeset some statistics. This can't be
+% done in the table footer, because the data is dynamic (e.g.,
+% number of glyphs processed) and the table footers are static and
+% do not change based on the table content.
+% \begin{macrocode}
+ \@@_handle_table_ending:n {#2}
+ \end{longtable\bool_if:NF\l_@@_display_header_bool{*}}
+ \group_end:
+}
+% \end{macrocode}
+% \end{macro}
+
+
+%
+% \begin{macro}{\fonttableglyphcount}
+% \begin{macro}{\g_@@_glyph_int,\g_@@_glyph_only_B_int,\g_@@_glyph_also_B_int}
+% While generating the font table we count the number of glyphs we
+% see (and typeset). The total is available in the command
+% \cs{fonttableglyphcount} after the table got finished and will be reset to
+% zero when the next table starts.
+% \begin{macrocode}
+\DeclareDocumentCommand \fonttableglyphcount {}
+ { \int_use:N \g_@@_glyph_int }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\int_new:N \g_@@_glyph_int
+% \end{macrocode}
+% When comparing fonts we also record data for the second font: the
+% number of glyphs in both and the number of glyphs only in the
+% second one.
+% \begin{macrocode}
+\int_new:N \g_@@_glyph_only_B_int
+\int_new:N \g_@@_glyph_also_B_int
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+
+
+
+
+% \subsection{The overall table layout}
+%
+%
+% \begin{macro}{\@@_setup_header_footer:nn}
+% Setting up header and footer lines of the table.
+% This macro receives the \textit{font name} and the \textit{font
+% features} specified by the user as its arguments.
+% \begin{macrocode}
+\cs_new:Npn \@@_setup_header_footer:nn #1#2{
+% \end{macrocode}
+% On the first page of the table the header may show a caption or
+% some other sort of title based on the value of
+% \cs{l_@@_display_header_bool}. The formatting is handled by
+% \cs{@@_format_table_title:nn} which can be customized through the
+% key \key{title-format}.
+% \begin{macrocode}
+ \bool_if:NT \l_@@_display_header_bool
+ { \@@_format_table_title:nn{#1}{#2} \@@_debug_nl:n{T}\\*[6pt] }
+% \end{macrocode}
+% We may also want to display a line of hex digits. This is
+% controlled through the key \key{hex-digits} that accepts different
+% values: \kval{head}, \kval{foot}, \kval{head+foo}, \kval{block}
+% (after a block title) or \kval{none}.
+% \begin{macrocode}
+ \bool_if:NT \l_@@_header_hex_digits_bool
+ { \@@_display_row_of_hex_digits: \@@_debug_nl:n{H}\\* }
+ \endfirsthead
+% \end{macrocode}
+% Headers for later table pages have a continuation title and
+% maybe a row of hex digits.
+% \begin{macrocode}
+ \bool_if:NT \l_@@_display_header_bool
+ { \@@_format_table_cont:nn{#1}{#2} \@@_debug_nl:n{T}\\*[6pt] }
+ \bool_if:NT \l_@@_header_hex_digits_bool
+ { \@@_display_row_of_hex_digits: \@@_debug_nl:n{H}\\* }
+ \endhead
+% \end{macrocode}
+% Footers of the table are either empty or show a row of hex digits.
+% \begin{macrocode}
+ \bool_if:NT \l_@@_footer_hex_digits_bool
+ { \@@_display_row_of_hex_digits: \@@_debug_nl:n{H}\\* }
+ \endfoot
+% \end{macrocode}
+% The footer of the last page of the table will always be
+% empty. Any special row, such as a row of hex digits, will be
+% provided in the table body. The reason is that we may want to
+% display statistics at the very end of the table and those can't be
+% placed into a static footer.
+% \begin{macrocode}
+ \endlastfoot
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_header_hex_digits_bool}
+% \begin{macro}{\l_@@_footer_hex_digits_bool}
+% \begin{macro}{\l_@@_blockwise_hex_digits_bool}
+% Here are the booleans we use in the code.
+% \begin{macrocode}
+\bool_new:N \l_@@_header_hex_digits_bool
+\bool_new:N \l_@@_footer_hex_digits_bool
+\bool_new:N \l_@@_blockwise_hex_digits_bool
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_display_row_of_hex_digits:}
+% \begin{macro}{\@@_format_hex_digit:n}
+% Producing a row of hex digits is simple.
+% \begin{macrocode}
+\cs_new:Npn \@@_display_row_of_hex_digits: {
+ & \@@_format_hex_digit:n{0} & \@@_format_hex_digit:n{1}
+ & \@@_format_hex_digit:n{2} & \@@_format_hex_digit:n{3}
+ & \@@_format_hex_digit:n{4} & \@@_format_hex_digit:n{5}
+ & \@@_format_hex_digit:n{6} & \@@_format_hex_digit:n{7}
+ & \@@_format_hex_digit:n{8} & \@@_format_hex_digit:n{9}
+ & \@@_format_hex_digit:n{A} & \@@_format_hex_digit:n{B}
+ & \@@_format_hex_digit:n{C} & \@@_format_hex_digit:n{D}
+ & \@@_format_hex_digit:n{E} & \@@_format_hex_digit:n{F} }
+% \end{macrocode}
+% Each digit is typeset in typewriter and in script size. We offer
+% font and color
+% customizations. Note that it is important to set an explicit
+% family. Otherwise the hex digits are formatted using the current
+% table font (which may or may not work at all).
+% \begin{macrocode}
+\cs_new:Npn \@@_format_hex_digit:n #1 {
+ \l_@@_hex_digits_font_tl \l_@@_color_tl #1 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+
+% \begin{macro}{\l_@@_color_tl}
+% The token list to hold definition if set up.
+% \begin{macrocode}
+\tl_new:N \l_@@_color_tl
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \keysetup{overall table}
+% Here are the definitions for the keys used in the code above:
+% \begin{macrocode}
+\keys_define:nn {@@} {
+% \end{macrocode}
+% The \key{header} key is a boolean that determines if a header
+% title should be produced (default)
+% \begin{macrocode}
+ ,header .bool_set:N = \l_@@_display_header_bool
+ ,header .default:n = true
+ ,header .initial:n = true
+% \end{macrocode}
+% To ease the setup we also support the key \key{noheader} which is
+% a short form for \texttt{header=false}.
+% \begin{macrocode}
+ ,noheader .bool_set_inverse:N = \l_@@_display_header_bool
+ ,noheader .default:n = true
+% \end{macrocode}
+% The default for the \key{title-format} key is to produce a
+% \cs{caption} listing the font name and any features (if
+% given). Note the \cs{IfValueTF} command (provided by
+% \texttt{xparse}) that checks if the second argument got any value
+% or has the special \texttt{--NoValue--} value.
+% \begin{macrocode}
+ ,title-format .cs_set:Np = \@@_format_table_title:nn #1#2
+ ,title-format .initial:n =
+ \IfValueTF{#2} { \caption{ #1~ (features:~ \texttt{\small#2}) } }
+ { \caption{ #1 } }
+% \end{macrocode}
+% The default continuation title ignores the given features, so the
+% formatting is somewhat simpler. It uses \verb=\caption[]{...}= to
+% make a caption that doesn't alter the table number.
+% \begin{macrocode}
+ ,title-cont-format .cs_set:Np = \@@_format_table_cont:nn #1#2
+ ,title-cont-format .initial:n = \caption[]{#1~ \emph{cont.}}
+% \end{macrocode}
+% The key \key{hex-digits} is implemented as a choice, where each
+% allowed value sets different booleans that are then used in the code.
+% \begin{macrocode}
+ ,hex-digits .choice:
+ ,hex-digits / block .code:n =
+ \bool_set_true:N \l_@@_blockwise_hex_digits_bool
+ \bool_set_false:N \l_@@_header_hex_digits_bool
+ \bool_set_false:N \l_@@_footer_hex_digits_bool
+ ,hex-digits / foot .code:n =
+ \bool_set_true:N \l_@@_footer_hex_digits_bool
+ \bool_set_false:N \l_@@_header_hex_digits_bool
+ \bool_set_false:N \l_@@_blockwise_hex_digits_bool
+ ,hex-digits / head .code:n =
+ \bool_set_true:N \l_@@_header_hex_digits_bool
+ \bool_set_false:N \l_@@_footer_hex_digits_bool
+ \bool_set_false:N \l_@@_blockwise_hex_digits_bool
+ ,hex-digits / head+foot .code:n =
+ \bool_set_true:N \l_@@_header_hex_digits_bool
+ \bool_set_true:N \l_@@_footer_hex_digits_bool
+ \bool_set_false:N \l_@@_blockwise_hex_digits_bool
+ ,hex-digits / none .code:n =
+ \bool_set_false:N \l_@@_header_hex_digits_bool
+ \bool_set_false:N \l_@@_footer_hex_digits_bool
+ \bool_set_false:N \l_@@_blockwise_hex_digits_bool
+ ,hex-digits .initial:n = head
+% \end{macrocode}
+% The font for hex digits are set with \key{hex-digits-font}.
+% \begin{macrocode}
+ ,hex-digits-font .tl_set:N = \l_@@_hex_digits_font_tl
+ ,hex-digits-font .initial:n = \ttfamily \scriptsize
+% \end{macrocode}
+% The \key{color} key is used in most places that get colored; some
+% have their own key but default to the main color.
+% \begin{macrocode}
+ ,color .choice:
+ ,color / none .code:n = \tl_clear:N \l_@@_color_tl
+ ,color / unknown .code:n = \tl_set:Nn \l_@@_color_tl { \color {#1} }
+ ,color .initial:n = blue
+ }
+% \end{macrocode}
+%
+%
+%
+%
+% \begin{macro}{\@@_handle_table_ending:n}
+% At the end of the table we may want to display a final row of
+% hex digits and perhaps some statistics, i.e., the number of
+% typeset glyphs.
+% \begin{macrocode}
+\cs_new:Npn \@@_handle_table_ending:n #1 {
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \@@_debug_nl:n{H} \\*
+ \bool_if:NT \l_@@_footer_hex_digits_bool
+ { \@@_display_row_of_hex_digits: \@@_debug_nl:n{H} \\* }
+ \bool_if:NT \l_@@_display_statistics_bool
+ { \\*[2pt]
+ \multicolumn{17}{l}{ \l_@@_stats_font_tl
+% \end{macrocode}
+% If we do font comparison, we use a different command for
+% displaying statistics and pass more data to it.
+% \begin{macrocode}
+ \tl_if_empty:NTF \l_@@_compare_with_tl
+ {
+ \@@_format_stats:nn{#1}{\fonttableglyphcount}
+ }
+ {
+ \@@_format_compare_stats:nnnnnn{#1}{\fonttableglyphcount}
+ { \l_@@_compare_with_tl }
+% \end{macrocode}
+% The extra arguments are total glyph number in second font, glyphs
+% missing in second font and glyphs only in second font.
+% \begin{macrocode}
+ { \int_eval:n { \int_use:N\g_@@_glyph_also_B_int +
+ \int_use:N\g_@@_glyph_only_B_int }
+ }
+ { \int_eval:n { \fonttableglyphcount -
+ \int_use:N\g_@@_glyph_also_B_int }
+ }
+ { \int_use:N\g_@@_glyph_only_B_int }
+ }
+% \end{macrocode}
+% We don't know exactly how wide the table is (and nor does the
+% user) but one may need to use \cs{parbox} when formatting
+% the statistic line(s). So we back up a bit (rather random) which
+% allows us to use \verb=\parbox{\linewidth}{...= in the key
+% without thinking too much about it.
+% \begin{macrocode}
+ \hspace*{-3cm}
+ }
+ }
+}
+% \end{macrocode}
+%
+% \keysetup{for statistics}
+% Here are the keys used above. By default we produce statistics.
+% \begin{macrocode}
+\keys_define:nn {@@} {
+ ,statistics .bool_set:N = \l_@@_display_statistics_bool
+ ,statistics .default:n = true
+ ,statistics .initial:n = true
+% \end{macrocode}
+% the key \key{nostatistics} is just short for \texttt{statistics=false}:
+% \begin{macrocode}
+ ,nostatistics .bool_set_inverse:N = \l_@@_display_statistics_bool
+ ,nostatistics .default:n = true
+% \end{macrocode}
+% The default font we use is \cs{normalfont}. Again we need to
+% supply a family to avoid getting the font used in the table body.
+% \begin{macrocode}
+ ,statistics-font .tl_set:N = \l_@@_stats_font_tl
+ ,statistics-font .initial:n = \normalfont\small
+% \end{macrocode}
+% And here we have the default text. There is only space for a
+% single line. If more text is needed one needs to provide some
+% explicit \cs{parbox}.
+% \begin{macrocode}
+ ,statistics-format .cs_set:Np = \@@_format_stats:nn #1#2
+ ,statistics-format .initial:n = Total~ number~ of~ glyphs~ in~ #1:~#2
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+%
+% \begin{macro}{\@@_debug_nl:n}
+% While developing the code I had a bit of trouble getting the line
+% endings correct, so I added a little macro that made them visible
+% (displaying its argument in the table margin when the key
+% \key{debug} is used. By default it does nothing.
+% \begin{macrocode}
+\cs_new:Npn \@@_debug_nl:n #1 {}
+% \end{macrocode}
+%
+% \keysetup{debugging}
+% This key is really internal and is therefore not documented above
+% (and its behavior may changes over time).
+% \begin{macrocode}
+\keys_define:nn {@@} {
+ debug .code:n = \cs_set:Npn \@@_debug_nl:n ##1
+ {\rlap{\normalfont\scriptsize \qquad ##1}} }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+%
+%
+%
+% \subsection{The producing the table content}
+%
+%
+% The body of the table consists of rows with sixteen glyphs each
+% and to produce it we loop through all possible Unicode points
+% starting at \texttt{U+0000} and ending with \texttt{U+FFFF}.
+%
+% This is implemented with a four-level nested loop that runs through the
+% values \texttt{0}, \texttt{1}, \ldots, \texttt{F} with the
+% current hex value in each of the four positions stored in some variable.
+
+
+% \begin{macro}{\g_@@_hex_H_tl,\g_@@_hex_A_tl,
+% \g_@@_hex_B_tl,\g_@@_hex_C_tl}
+% \cs{g_@@_hex_H_tl} is a bit special because, it is initially not
+% zero, but empty, so that slots in the lower plane are denoted by 4
+% hex digits.
+% We really only need three further variables, as the value in the
+% innermost loop can used directly.
+% \begin{macrocode}
+\tl_new:N \g_@@_hex_H_tl % higher plane
+\tl_new:N \g_@@_hex_A_tl
+\tl_new:N \g_@@_hex_B_tl
+\tl_new:N \g_@@_hex_C_tl
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\c_@@_hex_digits_clist}
+% Here is the sequence we loop through on each level, except the
+% one for the outer level.
+% \begin{macrocode}
+\clist_const:Nn\c_@@_hex_digits_clist{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\@@_produce_table_rows:,\@@_handle_hex_H:n,
+% \@@_handle_hex_A:n,\@@_handle_hex_B:n,
+% \@@_handle_hex_C:n,\@@_handle_hex_D:n}
+% The overall code layout is then fairly simply:
+% \begin{macrocode}
+\cs_new:Npn \@@_produce_table_rows: {
+% \end{macrocode}
+% First to some general initialization
+% \begin{macrocode}
+ \@@_initialize_table_rows:
+% \end{macrocode}
+% and then loop we start the loop. The outer level is a bit special
+% as currently Unicode has only slots allocated in plane 0, 1, 2
+% and E (well, and F, but that is a private area) so we loop only
+% over those and instead of \texttt{0} we use an empty value.
+% Not covered is the whole of plane 16 which too is now a
+% private area.
+%
+% \begin{macrocode}
+ \clist_map_function:nN { { } , 1, 2, E, F } \@@_handle_hex_H:n }
+% \end{macrocode}
+%
+% Most fonts do not have glyphs in the higher planes, which is why
+% by default we don't loop using a nonempty \cs{@@_handle_hex_H:n}.
+% But if the user wants to scan and display the higher slots they
+% can by setting \key{range-end} appropriatly.
+%
+% So after setting \cs{@@_handle_hex_H:n} we loop over
+% \cs{c_@@_hex_digits_clist} for the next
+% hex digit (which we call \enquote{A}).
+% \begin{macrocode}
+\cs_new:Npn \@@_handle_hex_H:n #1 { \tl_gset:Nn\g_@@_hex_H_tl{#1}
+ \clist_map_function:NN \c_@@_hex_digits_clist \@@_handle_hex_A:n }
+% \end{macrocode}
+%
+% Handling \enquote{A} means storing its value for later use and
+% then start a loop for setting the second (or third on higher planes) hex digits:
+% \begin{macrocode}
+\cs_new:Npn \@@_handle_hex_A:n #1 { \tl_gset:Nn\g_@@_hex_A_tl{#1}
+ \clist_map_function:NN \c_@@_hex_digits_clist \@@_handle_hex_B:n }
+% \end{macrocode}
+%
+% Same game for \enquote{B} and \enquote{C}\footnote{Actually this
+% is a white lie. In reality we do a lot of extra stuff when
+% handling \enquote{C} so later one we give a second definition for
+% \cs{@@_handle_hex_C:n} but for understanding the overall picture
+% the simpler one shown here is better.}:
+% \begin{macrocode}
+\cs_new:Npn \@@_handle_hex_B:n #1 { \tl_gset:Nn\g_@@_hex_B_tl{#1}
+ \clist_map_function:NN \c_@@_hex_digits_clist \@@_handle_hex_C:n }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new:Npn \@@_handle_hex_C:n #1 { \tl_gset:Nn\g_@@_hex_C_tl{#1}
+ \clist_map_function:NN \c_@@_hex_digits_clist \@@_handle_hex_D:n }
+% \end{macrocode}
+% In the innermost loop we now have the full Unicode number
+% available, so there we have to decide what to do with it. This is
+% done by \cs{@@_handle_hex_D:n} that receives the full number,
+% e.g., \texttt{1A7C} or \texttt{1AD00}, as its argument.
+% \begin{macrocode}
+\cs_new:Npn \@@_handle_hex_D:n #1 {
+ \@@_handle_slot:x
+ { " \g_@@_hex_H_tl \g_@@_hex_A_tl
+ \g_@@_hex_B_tl \g_@@_hex_C_tl #1 }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\g_@@_row_tl}
+% We first collect the glyphs for a whole row before deciding to
+% typeset it, because if the row is entirely empty we want to omit
+% it. The data for the row is collected slot by slot and the typesetting
+% information (the glyph or the indication for a missing glyph is
+% appended to \cs{g_@@_row_tl}.
+% \begin{macrocode}
+\tl_new:N \g_@@_row_tl
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_handle_slot:n,\@@_handle_slot:x}
+% If the current slot number under inspection contains a glyph in
+% our font we want to typeset it. But we don't do this immediately,
+% instead we build up the whole row and typeset it later. We
+% therefore append a \verb=&= and the glyph (including the necessary
+% formatting) to the token list \cs{g_@@_row_tl}.
+% \begin{macrocode}
+\cs_new:Npn \@@_handle_slot:n #1 {
+ \@@_if_uchar_exists:nTF { #1 }
+ { \tl_gput_right:Nn \g_@@_row_tl
+ { & \@@_format_glyph:n { \symbol{#1} } }
+% \end{macrocode}
+% We then increment the overall glyph count and record that we have
+% seen at least one glyph in the current row. There is not much
+% point in displaying rows that are completely empty; indeed,
+% we'd end up with extremely large tables which are
+% mostly empty.
+% \begin{macrocode}
+ \int_gincr:N\g_@@_glyph_int
+ \bool_gset_true:N \g_@@_glyph_seen_bool
+% \end{macrocode}
+% If we do font comparison we also check if the glyph is in the
+% second font and if so record that fact.
+% \begin{macrocode}
+ \tl_if_empty:NF \l_@@_compare_font_tl
+ {
+ \group_begin:
+ \l_@@_compare_font_tl
+ \@@_if_uchar_exists:nT { #1 }
+ { \int_gincr:N \g_@@_glyph_also_B_int }
+ \group_end:
+ }
+ }
+% \end{macrocode}
+% If the current slot has no glyph in the font we also add a
+% \verb=&= followed by something that indicates the glyph is
+% missing. If we do font comparison, it may show the glyph from
+% the other font (if it exists there) in some special way to indicate which glyph
+% should be in this slot.
+% \begin{macrocode}
+ { \@@_handle_missing_glyph:n {#1} }
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_generate_variant:Nn \@@_handle_slot:n {x}
+% \end{macrocode}
+% \end{macro}
+%
+
+% \begin{macro}{\@@_handle_missing_glyph:n,
+% \@@_handle_missing_glyph_std:n,
+% \@@_handle_missing_glyph_compare:n}
+%
+% In the standard case we typeset a special symbol to indicate that the glyph is missing.
+% For this case we provide some customization through keys:
+% \cs{l_@@_missing_glyph_tl} holds the symbol for a missing glyph
+% (default: a hyphen). It is typeset in a specific color and we allow for
+% setting it in a special font. The actual symbol number in
+% \verb=#1= is not needed in this scenario.
+% \begin{macrocode}
+\cs_new:Npn \@@_handle_missing_glyph_std:n #1 {
+ \tl_gput_right:Nn \g_@@_row_tl
+ { &
+ \@@_format_glyph:n {
+% \colorbox{black!30} % <--- povide interface
+ {\l_@@_missing_glyph_color_tl
+ \l_@@_missing_glyph_font_tl
+ \l_@@_missing_glyph_tl }
+ }
+ }
+}
+% \end{macrocode}
+%
+% \keysetup{missing glyphs}
+% Here are the keys for customizing the missing glyph representation.
+% \begin{macrocode}
+\keys_define:nn {@@} {
+ missing-glyph-color .choice:
+ ,missing-glyph-color / none .code:n =
+ \tl_clear:N \l_@@_missing_glyph_color_tl
+ ,missing-glyph-color / unknown .code:n =
+ \tl_set:Nn \l_@@_missing_glyph_color_tl { \color {#1} }
+%
+ ,missing-glyph-font .tl_set:N = \l_@@_missing_glyph_font_tl
+ ,missing-glyph-font .initial:n = \ttfamily \scriptsize
+ ,missing-glyph .tl_set:N = \l_@@_missing_glyph_tl
+ ,missing-glyph .initial:n = - }
+% \end{macrocode}
+%
+%
+% The default definition for the color is to use the same as the
+% one specified by the \key{color} key. We therefore define the
+% default outside of the \pkg{l3keys} method.
+% \begin{macrocode}
+\tl_new:N \l_@@_missing_glyph_color_tl
+\tl_set:Nn \l_@@_missing_glyph_color_tl {\l_@@_color_tl}
+% \end{macrocode}
+%
+% This is the version that handles a missing glyph by checking
+% the \key{compare-with} font to see if that font contains the
+% glyph.
+% If yes, the substitute glyph will be typeset, otherwise the missing
+% glyph symbol is shown by calling \cs{@@_handle_missing_glyph_std:n}.
+% \begin{macrocode}
+\cs_new:Npn \@@_handle_missing_glyph_compare:n #1 {
+ \group_begin:
+% \end{macrocode}
+% Locally switch to the other font, then check for the glyph:
+% \begin{macrocode}
+ \l_@@_compare_font_tl
+ \@@_if_uchar_exists:nTF { #1 }
+ {
+% \end{macrocode}
+% If available, format it (together with the \texttt{\&}) but use a
+% special color and perhaps a background color.
+% \begin{macrocode}
+ \tl_gput_right:Nn \g_@@_row_tl
+ { &
+ \@@_format_glyph:n
+ { \l_@@_compare_bgcolor_tl { \l_@@_compare_color_tl
+ \l_@@_compare_font_tl
+ \symbol {#1} }
+ }
+ }
+% \end{macrocode}
+% Having seen a glyph only in the second font we record this fact.
+% \begin{macrocode}
+ \int_gincr:N \g_@@_glyph_only_B_int
+% \end{macrocode}
+% Also tell the algorithm that we have seen a glyph to typeset. If
+% we don't do this then a row consisting of only substitute glyphs is not
+% typeset. However, we don't update the glyph count, because this
+% is not a glyph from the main font we display.
+% \begin{macrocode}
+ \bool_gset_true:N \g_@@_glyph_seen_bool
+ }
+% \end{macrocode}
+% If the alternate font doesn't have the glyph either we
+% typeset the missing glyph symbol.
+% \begin{macrocode}
+ { \@@_handle_missing_glyph_std:n {} }
+ \group_end:
+}
+% \end{macrocode}
+%
+% \keysetup{comparison}
+%
+% In order to display glyphs from a secondary font we need a
+% secondary color for the glyph itself and possibly some background color.
+% \begin{macrocode}
+\tl_new:N \l_@@_compare_with_tl
+\tl_new:N \l_@@_compare_color_tl
+\tl_new:N \l_@@_compare_bgcolor_tl
+% \end{macrocode}
+%
+% \begin{macrocode}
+\keys_define:nn {@@}
+ {
+ ,compare-with .tl_set:N = \l_@@_compare_with_tl
+ ,compare-with .initial:n =
+ ,compare-color .choice:
+ ,compare-color / none .code:n
+ = \tl_clear:N \l_@@_compare_color_tl
+ ,compare-color / unknown .code:n
+ = \tl_set:Nn \l_@@_compare_color_tl { \color {#1} }
+ ,compare-color .initial:n = red
+ ,compare-bgcolor .choice:
+ ,compare-bgcolor / none .code:n
+ = \tl_clear:N \l_@@_compare_bgcolor_tl
+ ,compare-bgcolor / unknown .code:n
+ = \tl_set:Nn \l_@@_compare_bgcolor_tl { \colorbox {#1} }
+ ,compare-bgcolor .initial:n = black!10
+% \end{macrocode}
+% If we run a comparison we show different statistics that have
+% their own key.
+% \begin{macrocode}
+ ,statistics-compare-format .cs_set:Np
+ = \@@_format_compare_stats:nnnnnn #1#2#3#4#5#6
+ ,statistics-compare-format .initial:n
+ = \parbox{\linewidth}{
+ Total~ number~ of~ glyphs~ in~ \texttt{#1}:~#2\\
+ Comparison~ font~ \texttt{#3}~ has~ #5~ missing~ and~ #6~
+ extra~ glyphs}
+ }
+% \end{macrocode}
+%
+%
+% By default, i.e., if no font for comparison has been specified, we
+% handle missing glyphs by displaying a missing glyph symbol.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_handle_missing_glyph:n
+ \@@_handle_missing_glyph_std:n
+% \end{macrocode}
+% \end{macro}
+%
+
+
+% \begin{macro}{\@@_format_glyph:n}
+% Every glyph is typeset in a box of equal width with the glyph
+% centered and if necessary protruding on both sides.
+% \begin{macrocode}
+\cs_new:Npn \@@_format_glyph:n #1 {
+ \hbox_to_wd:nn {\l_@@_glyph_box_dim} { \hss #1 \hss } }
+% \end{macrocode}
+%
+% \keysetup{glyph typesetting}
+% The key to customize the width. The 6pt are fine for most cases.
+% \begin{macrocode}
+\dim_new:N\l_@@_glyph_box_dim
+% \end{macrocode}
+%
+% \begin{macrocode}
+\keys_define:nn {@@} {
+ glyph-width .dim_set:N = \l_@@_glyph_box_dim
+ ,glyph-width .initial:n = 6pt
+}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_if_uchar_exists:n}
+% For testing whether or not a slot position contains a glyph we
+% need to resort to low-level methods, because so far
+% \texttt{expl3} doesn't offer an interface.
+% \begin{macrocode}
+\prg_set_conditional:Npnn \@@_if_uchar_exists:n #1 { TF , T }
+ { \tex_iffontchar:D \tex_font:D #1 \scan_stop:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+%
+% \subsection{Handling a single row}
+%
+%
+% \begin{macro}{\@@_handle_hex_C:n}
+% As promised here is the read definition for
+% \cs{@@_handle_hex_C:n} in all its glory.
+% \begin{macrocode}
+\cs_set:Npn \@@_handle_hex_C:n #1 {
+% \end{macrocode}
+% We are now at the start of a new row (but with the last row not
+% yet typeset) and this last row may need a Unicode block heading
+% before it. This is the reason why we have to delay the
+% typesetting, because in case the line doesn't contain any glyphs
+% we want to typeset neither and that is only known after all
+% slots in the row have been processed.
+% \begin{macrocode}
+ \@@_maybe_typeset_a_row_and_display_a_block_title:
+% \end{macrocode}
+% We then store away the value for the third hex digit (denoted as
+% C) in order to start with the next row.
+% \begin{macrocode}
+ \tl_gset:Nn\g_@@_hex_C_tl{#1}
+% \end{macrocode}
+% Being at the start of a new row we might be at the start of a new
+% Unicode block. If so we have to update the block title to add in
+% front of the row when we typeset it (or in front of one of the
+% next rows if the first rows in the is block have no glyphs). If
+% we are still in the same block no update happens.
+% \begin{macrocode}
+ \@@_update_block_title:n { \g_@@_hex_H_tl
+ \g_@@_hex_A_tl
+ \g_@@_hex_B_tl
+ \g_@@_hex_C_tl }
+% \end{macrocode}
+% We now check if this row is within the requested range, i.e.,
+% greater than or equal to \cs{l_@@_range_start_tl} and not greater than
+% \cs{l_@@_range_end_tl}.
+% \begin{macrocode}
+ \int_compare:nNnF
+ { " \g_@@_hex_H_tl \g_@@_hex_A_tl
+ \g_@@_hex_B_tl \g_@@_hex_C_tl 0 }
+ < { "\l_@@_range_start_tl }
+ {
+ \int_compare:nNnTF
+ { " \g_@@_hex_H_tl \g_@@_hex_A_tl
+ \g_@@_hex_B_tl \g_@@_hex_C_tl 0 }
+ > { "\l_@@_range_end_tl }
+% \end{macrocode}
+% If we are past the \texttt{end-range} we break out the clist
+% mapping, to avoind unnecessary repetition. This should be
+% propagated back to the outer clists as well (not done).
+% \begin{macrocode}
+ { \clist_map_break: }
+% \end{macrocode}
+% If we are within range we process the slots in the row by first
+% initializing \cs{g_@@_row_tl} with the row title (the info on the
+% left) and then loop through all slots the row to append glyphs
+% (or missing glyphs) to \cs{g_@@_row_tl} to build up everything we
+% need to finally typeset it.
+% \begin{macrocode}
+ {
+ \tl_gset:Nx \g_@@_row_tl
+ {
+ \exp_not:N \@@_format_row_title:n
+ { \g_@@_hex_H_tl \g_@@_hex_A_tl
+ \g_@@_hex_B_tl \g_@@_hex_C_tl }
+ }
+ \clist_map_function:NN \c_@@_hex_digits_clist
+ \@@_handle_hex_D:n
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_format_row_title:n}
+% The function to format the row title on the left, as used above.
+% \begin{macrocode}
+\cs_new:Npn \@@_format_row_title:n #1 {
+ \texttt { \footnotesize \l_@@_color_tl U+#1 0 \, - \, #1 F }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \keysetup{ranges}
+%
+% For the range we have two keys, its start and the end. By default the
+% whole range from 0 to FFFF is processed.
+%
+% \begin{macrocode}
+\tl_new:N \l_@@_range_start_tl
+\tl_new:N \l_@@_range_end_tl
+% \end{macrocode}
+%
+% \begin{macrocode}
+\keys_define:nn {@@}
+ {
+ ,range-start .tl_set:N = \l_@@_range_start_tl
+ ,range-start .initial:n = 0000
+ ,range-end .tl_set:N = \l_@@_range_end_tl
+ ,range-end .initial:n = FFFF
+ }
+% \end{macrocode}
+%
+%
+%
+%
+%
+% \begin{macro}{\@@_maybe_typeset_a_row_and_display_a_block_title:}
+% The function handles the just-finished row and, if the row does not
+% consist only of missing glyphs, typesets it. If necessary it also typesets
+% a Unicode block name first.
+% \begin{macrocode}
+\cs_new:Npn \@@_maybe_typeset_a_row_and_display_a_block_title: {
+% \end{macrocode}
+% We first check if the row had any real glyphs.
+% \begin{macrocode}
+ \bool_if:NTF \g_@@_glyph_seen_bool
+ {
+% \end{macrocode}
+% If the row needs typesetting the fun part starts. We first look
+% at the content of \cs{g_@@_block_title_tl}.
+% \begin{macrocode}
+ \tl_if_empty:NTF \g_@@_block_title_tl
+ {
+% \end{macrocode}
+% It is empty we are in the middle of a block and we can ignore
+% the Unicode title. However, we have to see if the previous row
+% (or several) was missing (i.e., contained no glyphs). In that
+% case we leave a little extra space, otherwise we just finish the
+% previous row
+% \begin{macrocode}
+ \bool_if:NTF \g_@@_row_missing_bool
+ { \@@_debug_nl:n{A}\\[6pt] }
+ { \@@_debug_nl:n{B}\\ }
+ }
+ {
+% \end{macrocode}
+% Otherwise we first have to typeset the Unicode block title (or
+% whatever should happen instead).
+% \begin{macrocode}
+ \typeout{ Processing~ \tl_use:N \g_@@_block_title_tl }
+ \bool_if:NTF \l_@@_display_block_bool
+ {
+% \end{macrocode}
+% If we are to typeset the title the action depends a bit on
+% whether we are at the very first row or typesetting a later block.
+% \begin{macrocode}
+ \bool_if:NTF \g_@@_first_row_bool
+ {
+ \bool_gset_false:N \g_@@_first_row_bool
+ \@@_debug_nl:n{C}\\[-4pt]
+ }
+ {
+ \@@_debug_nl:n{D}\\[8pt]
+ \noalign{\vskip 1pt plus 1pt} % space above block: customizable?
+ }
+% \noalign{\smallskip} % space above block: customizable?
+ \multicolumn{17}{c}{\normalfont \bfseries
+ \tl_use:N \g_@@_block_title_tl}
+% \end{macrocode}
+% After the block title is typeset we may want to add a row of hex
+% digits as well if that was requested, otherwise we only leave a
+% bit of extra space.
+% \begin{macrocode}
+ \bool_if:NTF \l_@@_blockwise_hex_digits_bool
+ { \@@_debug_nl:n{E}\\*
+ \@@_display_row_of_hex_digits:
+ \@@_debug_nl:n{H}\\*[2pt]
+ }
+ { \@@_debug_nl:n{F}\\*[2pt] }
+ }
+ {
+% \end{macrocode}
+% If the Unicode block title is not typeset we may still have to do
+% someting special and again it differs if we at the very beginning
+% of the table (because there we do nothing except changing the
+% state of \cs{g_@@_first_row_bool}).
+% \begin{macrocode}
+ \bool_if:NTF \g_@@_first_row_bool
+ { \bool_gset_false:N \g_@@_first_row_bool }
+ {
+ \@@_debug_nl:n{G~ (new~ block)}
+ \l_@@_display_block_action_tl
+ }
+ }
+% \end{macrocode}
+% Once we are past the block title we clear it, so that it is not
+% retypeset before the next row.
+% \begin{macrocode}
+ \tl_gclear:N \g_@@_block_title_tl
+ }
+% \end{macrocode}
+% The final action is to typeset the row and reset the booleans (in
+% case they were true; if they are false already then we do this
+% unnecessarily, but that is probably faster than testing first).
+% \begin{macrocode}
+ \bool_gset_false:N \g_@@_glyph_seen_bool
+ \bool_gset_false:N \g_@@_row_missing_bool
+ \tl_use:N \g_@@_row_tl
+ }
+% \end{macrocode}
+% Current row had no glyphs; remember that fact, and that is all we
+% have to do in that case.
+% \begin{macrocode}
+ {
+ \bool_gset_true:N \g_@@_row_missing_bool
+ }
+}
+% \end{macrocode}
+% \end{macro}
+
+%
+%
+% \subsection{Initialisation at the start of the table}
+%
+%
+% \begin{macro}{\g_@@_first_row_bool,\g_@@_glyph_seen_bool,\g_@@_row_missing_bool}
+% Declare the three booleans used in the code below. They will tell
+% us answers to the following questions:
+% \begin{itemize}
+% \item Are we processing the first row?
+% \item Have we seen any glyph so far (in the current row)?
+% \item Did we have one or more missing rows recently?
+% \end{itemize}
+% \begin{macrocode}
+\bool_new:N \g_@@_first_row_bool
+\bool_new:N \g_@@_glyph_seen_bool
+\bool_new:N \g_@@_row_missing_bool
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+
+
+% \begin{macro}{\@@_initialize_table_rows:}
+% At the start of a table we are processing the first row
+% and so we (obviously) haven't seen a glyph yet and there wasn't a
+% missing row recently.
+% \begin{macrocode}
+\cs_new:Npn \@@_initialize_table_rows: {
+ \bool_gset_true:N \g_@@_first_row_bool
+ \bool_gset_false:N \g_@@_glyph_seen_bool
+ \bool_gset_false:N \g_@@_row_missing_bool
+% \end{macrocode}
+% And clearly the glyph count for the font(s) is zero.
+% \begin{macrocode}
+ \int_gzero:N \g_@@_glyph_int
+ \int_gzero:N \g_@@_glyph_only_B_int
+ \int_gzero:N \g_@@_glyph_also_B_int
+}
+% \end{macrocode}
+% \end{macro}
+
+
+%
+%
+% \subsection{Handling block titles}
+%
+% \begin{macro}{g_@@_block_title_tl}
+% We keep the current block title in this token list.
+% \begin{macrocode}
+\tl_new:N \g_@@_block_title_tl
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_update_block_title:n}
+% A block title is updated when the hex digits A,B,C have a certain
+% value, so this is nothing more than a huge case switch.
+% \begin{macrocode}
+\cs_new:Npn \@@_update_block_title:n #1 {
+ \tl_gset:Nx \g_@@_block_title_tl {
+ \int_case:nnF{ "#1 }
+ {
+ { "000 }{ Basic~ Latin }
+ { "008 }{ Latin-1~ Supplement }
+ { "010 }{ Latin~ Extended-A }
+ { "018 }{ Latin~ Extended-B }
+ { "025 }{ IPA~ Extensions }
+ { "02B }{ Spacing~ Modifier~ Letters }
+ { "030 }{ Combining~ Diacritical~ Marks }
+ { "037 }{ Greek~ and~ Coptic }
+ { "040 }{ Cyrillic }
+ { "053 }{ Armenian }
+ { "059 }{ Hebrew }
+ { "060 }{ Arabic }
+ { "070 }{ Syriac }
+ { "075 }{ Arabic~ Supplement }
+ { "078 }{ Thaana }
+ { "07C }{ NKo }
+ { "090 }{ Devanagari }
+ { "098 }{ Bengali }
+ { "0A0 }{ Gurmukhi }
+ { "0A8 }{ Gujarati }
+ { "0B0 }{ Oriya }
+ { "0B8 }{ Tamil }
+ { "0C0 }{ Telugu }
+ { "0C8 }{ Kannada }
+ { "0D0 }{ Malayalm }
+ { "0D8 }{ Sinhala }
+ { "0E0 }{ Thai }
+ { "0E8 }{ Lao }
+ { "0F0 }{ Tibetan }
+ { "100 }{ Myanmar }
+ { "10A }{ Georgian }
+ { "110 }{ Hangul~ Jamo }
+ { "120 }{ Ethiopic }
+ { "138 }{ Ethiopic~ Supplement }
+ { "13A }{ Cherokee }
+ { "140 }{ Unified~ Canadian~ Aboriginal~ Syllabics }
+ { "168 }{ Ogham }
+ { "16A }{ Runic }
+ { "170 }{ Tagalog }
+ { "172 }{ Hanunoo }
+ { "174 }{ Buhid }
+ { "176 }{ Tagbanwa }
+ { "178 }{ Khmer }
+ { "180 }{ Mongolian }
+ { "190 }{ Limbu }
+ { "195 }{ Tai~ Le }
+ { "198 }{ New~ Tai~ Le }
+ { "19E }{ Khmer~ Symbols }
+ { "1A0 }{ Buginese }
+ { "1B0 }{ Balinese }
+ { "1D0 }{ Phonetic~ Extensions }
+ { "1D8 }{ Phonetic~ Extensions~ Supplement }
+ { "1DC }{ Combining~ Diacritical~ Marks~ Supplement }
+ { "1E0 }{ Latin~ Extended~ Additional }
+ { "1F0 }{ Greek~ Extended }
+ { "200 }{ General~ Punctuation }
+ { "207 }{ Superscripts~ and~ Subscripts }
+ { "20A }{ Currency~ Symbols }
+ { "20D }{ Combining~ Diacritical~ Marks~ for~ Symbols }
+ { "210 }{ Letterlike~ Symbols }
+ { "215 }{ Number~ Forms }
+ { "219 }{ Arrows }
+ { "220 }{ Mathematical~ Operators }
+ { "230 }{ Miscellaneous~ Technical }
+ { "240 }{ Control~ Pictures }
+ { "244 }{ Optical~ Character~ Recognition }
+ { "246 }{ Enclosed~ Alphanumerics }
+ { "250 }{ Box~ Drawing }
+ { "258 }{ Block~ Elements }
+ { "25A }{ Geometric~ Shapes }
+ { "260 }{ Miscellaneous~ Shapes }
+ { "270 }{ Dingbats }
+ { "27C }{ Miscellaneous~ Mathematical~ Symbols-A }
+ { "27F }{ Supplemental~ Arrows-A }
+ { "280 }{ Braille~ Patterns }
+ { "290 }{ Supplemental~ Arrows-B }
+ { "298 }{ Miscellaneous~ Mathematical~ Symbols-B }
+ { "2A0 }{ Supplemental~ Mathematical~ Operators }
+ { "2B0 }{ Miscellaneous~ Symbols~ and~ Arrows }
+ { "2C0 }{ Glagolitic }
+ { "2C6 }{ Latin~ Extended-C }
+ { "2C8 }{ Coptic }
+ { "2D0 }{ Georgian~ Supplement }
+ { "2D3 }{ Tifinagh }
+ { "2D8 }{ Ethiopic~ Extended }
+ { "2E0 }{ Supplemental~ Punctuation }
+ { "2E8 }{ CJK~ Radicals~ Supplement }
+ { "2F0 }{ Kangxi~ Radicals }
+ { "2FF }{ Ideographic~ Description~ Characters }
+ { "300 }{ CJK~ Symbols~ and~ Punctuation }
+ { "304 }{ Hiragana }
+ { "30A }{ Katakana }
+ { "310 }{ Bopomofo }
+ { "313 }{ Hangul~ Compatibility~ Jamo }
+ { "319 }{ Kanbun }
+ { "31A }{ Bopomofo~ Extended }
+ { "31C }{ CJK~ Strokes }
+ { "31F }{ Katakana~ Phonetic~ Extensions }
+ { "320 }{ Enclosed~ CJK~ Letters~ and~ Months }
+ { "330 }{ CJK~ Compatibility }
+ { "4DC }{ Yijing~ Hexagram~ Symbols }
+ { "A00 }{ Yi~ Syllables }
+ { "A49 }{ Yi~ Radicals }
+ { "A70 }{ Modifier~ Tone~ Letters }
+ { "A72 }{ Latin~ Extended-D }
+ { "A80 }{ Syloti~ Nagri }
+ { "A84 }{ Phags-pa }
+ { "A88 }{ Saurashtra }
+ { "A8E }{ Devanagari Extended }
+ { "A90 }{ Kayah Li }
+ { "A93 }{ Rejang }
+ { "A96 }{ Hangul Jamo Extended-A }
+ { "A98 }{ Javanese }
+ { "A9E }{ Myanmar Extended-B }
+ { "AA0 }{ Cham }
+ { "AA6 }{ Myanmar Extended-A }
+ { "AA8 }{ Tai Viet }
+ { "AAE }{ Meetei Mayek Extensions }
+ { "AB0 }{ Ethiopic Extended-A }
+ { "AB3 }{ Latin Extended-E }
+ { "AB7 }{ Cherokee Supplement }
+ { "ABC }{ Meetei Mayek }
+ { "AC0 }{ Hangul Syllables }
+ { "D7B }{ Hangul Jamo Extended-B }
+ { "D80 }{ High Surrogates }
+ { "DB8 }{ High Private Use Surrogates }
+ { "DC0 }{ Low Surrogates }
+ { "E00 }{ Private~ Use~ Area }
+ { "F90 }{ CJK~ Compatibility~ Ideographs }
+ { "FB0 }{ Alphabetic~ Presentation~ Forms }
+ { "FB5 }{ Arabic~ Presentation~ Forms-A }
+ { "FE0 }{ Variation~ Selectors }
+ { "FE1 }{ Vertical~ Forms }
+ { "FE2 }{ Combining~ Half~ Marks }
+ { "FE3 }{ CJK~ Compatibility~ Forms }
+ { "FE5 }{ Small~ Form~ Variants }
+ { "FE7 }{ Arabic~ Presentation~ Forms-B }
+ { "FF0 }{ Halfwidth~ and Fullwidth~ Forms }
+ { "FFF }{ Specials~ ... }
+%% ... Plane 1 ...
+ { "1000 }{ Linear~ B~ Syllabary }
+ { "1008 }{ Linear~ B~ Ideograms }
+ { "1010 }{ Aegean~ Numbers }
+ { "1014 }{ Ancient~ Greek~ Numbers }
+ { "1019 }{ Ancient~ Symbols }
+ { "101D }{ Phaistos~ Disc }
+ { "1028 }{ Lycian }
+ { "102A }{ Carian }
+ { "102E }{ Coptic~ Epact~ Numbers }
+ { "1030 }{ Old~ Italic }
+ { "1033 }{ Gothic }
+ { "1035 }{ Old~ Permic }
+ { "1038 }{ Ugaritic }
+ { "103A }{ Old~ Persian }
+ { "1040 }{ Deseret }
+ { "1045 }{ Shavian }
+ { "1048 }{ Osmanya }
+ { "104B }{ Osage }
+ { "1050 }{ Elbasan }
+ { "1053 }{ Caucasian~ Albanian }
+ { "1060 }{ Linear~ A }
+ { "1080 }{ Cypriot~ Syllabary }
+ { "1084 }{ Imperial~ Aramaic }
+ { "1086 }{ Palmyrene }
+ { "1088 }{ Nabataean }
+ { "108E }{ Hatran }
+ { "1090 }{ Phoenician }
+ { "1092 }{ Lydian }
+ { "1098 }{ Meroitic~ Hieroglyphs }
+ { "109A }{ Meroitic~ Cursive }
+ { "10A0 }{ Kharoshthi }
+ { "10A6 }{ Old~ South~ Arabian }
+ { "10A8 }{ Old~ North~ Arabian }
+ { "10AC }{ Manichaean }
+ { "10B0 }{ Avestan }
+ { "10B4 }{ Inscriptional~ Parthian }
+ { "10B6 }{ Inscriptional~ Pahlavi }
+ { "10B8 }{ Psalter~ Pahlavi }
+ { "10C0 }{ Old~ Turkic }
+ { "10C8 }{ Old~ Hungarian }
+ { "10E6 }{ Rumi~ Numeral~ Symbols }
+ { "1100 }{ Brahmi }
+ { "1108 }{ Kaithi }
+ { "110D }{ Sora~ Sompeng }
+ { "1110 }{ Chakma }
+ { "1115 }{ Mahajani }
+ { "1118 }{ Sharada }
+ { "111E }{ Sinhala~ Archaic~ Numbers }
+ { "1120 }{ Khojki }
+ { "1128 }{ Multani }
+ { "112B }{ Khudawadi }
+ { "1130 }{ Grantha }
+ { "1140 }{ Newa }
+ { "1148 }{ Tirhuta }
+ { "1158 }{ Siddham }
+ { "1160 }{ Modi }
+ { "1166 }{ Mongolian~ Supplement }
+ { "1168 }{ Takri }
+ { "1170 }{ Ahom }
+ { "118A }{ Warang~ Citi }
+ { "11A0 }{ Zanabazar~ Square }
+ { "11A5 }{ Soyombo }
+ { "11AC }{ Pau~ Cin~ Hau }
+ { "11C0 }{ Bhaiksuki }
+ { "11C7 }{ Marchen }
+ { "11D0 }{ Masaram~ Gondi }
+ { "1200 }{ Cuneiform }
+ { "1240 }{ Cuneiform~ Numbers~ and~ Punctuation }
+ { "1248 }{ Early~ Dynastic~ Cuneiform }
+ { "1300 }{ Egyptian~ Hieroglyphs }
+ { "1440 }{ Anatolian~ Hieroglyphs }
+ { "1680 }{ Bamum~ Supplement }
+ { "16A4 }{ Mro }
+ { "16AD }{ Bassa~ Vah }
+ { "16B0 }{ Pahawh~ Hmong }
+ { "16F0 }{ Miao }
+ { "16FE }{ Ideographic~ Symbols~ and~ Punctuation }
+ { "1700 }{ Tangut }
+ { "1880 }{ Tangut~ Components }
+ { "1B00 }{ Kana~ Supplement }
+ { "1B10 }{ Kana~ Extended-A }
+ { "1B17 }{ Nushu }
+ { "1BC0 }{ Duployan }
+ { "1BCA }{ Shorthand~ Format~ Controls }
+ { "1D00 }{ Byzantine~ Musical~ Symbols }
+ { "1D10 }{ Musical~ Symbols }
+ { "1D20 }{ Ancient~ Greek~ Musical~ Notation }
+ { "1D30 }{ Tai~ Xuan~ Jing~ Symbols }
+ { "1D36 }{ Counting~ Rod~ Numerals }
+ { "1D40 }{ Mathematical~ Alphanumeric~ Symbols }
+ { "1D80 }{ Sutton~ SignWriting }
+ { "1E00 }{ Glagolitic~ Supplement }
+ { "1E80 }{ Mende~ Kikakui }
+ { "1E90 }{ Adlam }
+ { "1EE0 }{ Arabic~ Mathematical~ Alphabetic~ Symbols }
+ { "1F00 }{ Mahjong~ Tiles }
+ { "1F03 }{ Domino~ Tiles }
+ { "1F0A }{ Playing~ Cards }
+ { "1F10 }{ Enclosed~ Alphanumeric~ Supplement }
+ { "1F20 }{ Enclosed~ Ideographic~ Supplement }
+ { "1F30 }{ Miscellaneous~ Symbols~ and~ Pictographs }
+ { "1F60 }{ Emoticons }
+ { "1F65 }{ Ornamental~ Dingbats }
+ { "1F68 }{ Transport~ and~ Map~ Symbols }
+ { "1F70 }{ Alchemical~ Symbols }
+ { "1F78 }{ Geometric~ Shapes~ Extended }
+ { "1F80 }{ Supplemental~ Arrows-C }
+ { "1F90 }{ Supplemental~ Symbols~ and~ Pictographs }
+ { "2000 }{ CJK~ Unified~ Ideographs~ Extension~ B }
+ { "2A70 }{ CJK~ Unified~ Ideographs~ Extension~ C }
+ { "2B74 }{ CJK~ Unified~ Ideographs~ Extension~ D }
+ { "2B82 }{ CJK~ Unified~ Ideographs~ Extension~ E }
+ { "2CEB }{ CJK~ Unified~ Ideographs~ Extension~ F }
+ { "2F80 }{ CJK~ Compatibility~ Ideographs~ Supplement }
+ { "E010 }{ Tags }
+ { "E000 }{ Variation~ Selectors~ Supplement }
+ { "F000 }{ Supplementary~ Private~ Use~ Area-A }
+% higher up not covered!
+ }
+% \end{macrocode}
+% If none of the above has matched we are somewhere within a block
+% so we want keep the current name. However, since the case
+% statement was executed within a |\tl_gset:Nx| we have to do this
+% by passing the current block name back.
+% \begin{macrocode}
+ { \tl_use:N \g_@@_block_title_tl }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \keysetup{display blocks}
+%
+% The Unicode blocks may get indicated in different ways: with titles,
+% only through rules, or not at all. Here is the necessary setup.
+%
+% \begin{macrocode}
+\bool_new:N \l_@@_display_block_bool
+\tl_new:N \l_@@_display_block_action_tl
+% \end{macrocode}
+%
+% \begin{macrocode}
+\keys_define:nn {@@}
+ {
+ ,display-block .choice:
+ ,display-block / titles .code:n =
+ \bool_set_true:N \l_@@_display_block_bool
+ \tl_set:Nn \l_@@_display_block_action_tl {\\}
+ ,display-block / rules .code:n =
+ \bool_set_false:N \l_@@_display_block_bool
+ \tl_set:Nn \l_@@_display_block_action_tl {\\ \midrule}
+ ,display-block / none .code:n =
+ \bool_set_false:N \l_@@_display_block_bool
+ \tl_set:Nn \l_@@_display_block_action_tl {\\}
+ ,display-block .initial:n = titles
+ }
+% \end{macrocode}
+%
+%
+% That's all of the programming using the L3 layer.
+% \begin{macrocode}
+\ExplSyntaxOff
+% \end{macrocode}
+% What remains is to require all packages needed \ldots
+% \begin{macrocode}
+\RequirePackage{longtable,booktabs,caption,fontspec}
+% \end{macrocode}
+% \ldots and executing all options passed to the
+% package via \cs{usepackage}.
+% \begin{macrocode}
+\ProcessKeysPackageOptions{@@}
+%</package>
+% \end{macrocode}
+%
+%
+%
+%
+%
+% \section{The standalone \texttt{unicodefont.tex} file}
+%
+% \begin{macrocode}
+%<*standalone>
+\documentclass{article}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\setlength\textwidth{470pt}
+\setlength\oddsidemargin{0pt}
+\addtolength\textheight{7\baselineskip}
+\addtolength\topmargin{-3\baselineskip}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\usepackage{unicodefonttable}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\DEFAULTfontname{Latin Modern Roman}
+\def\DEFAULTfontfeatures{}
+\def\DEFAULTtableconfig{}
+\def\DEFAULTunicodefont{}
+\begin{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\typeout{^^J}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ifx\generatetable\undefined
+\else
+ \typein[\answer]{^^JReuse settings from last time (default yes)?^^J^^J%
+ [ font name = \DEFAULTfontname^^J
+ \space unicode? = \ifx\DEFAULTunicodefont\empty yes^^J
+ \space font features = \DEFAULTfontfeatures
+ \else no\fi^^J
+ \space table config = \DEFAULTtableconfig \space]}
+\fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ifx\answer\empty
+ \let\FontNameToTable\DEFAULTfontname
+ \let\IsUnicodeFont\DEFAULTunicodefont
+ \let\FontFeaturesToApply\DEFAULTfontfeatures
+ \let\TableConfigurationToApply\DEFAULTtableconfig
+\else
+% \end{macrocode}
+%
+% \begin{macrocode}
+\typein[\FontNameToTable]%
+ {^^JInput external font name as understood by fontspec, e.g.,^^J%
+ 'TeX Gyre Pagella' or 'lmroman10-regular.otf'%
+ \ifx\DEFAULTfontname\empty\else
+ ^^J^^J[default \DEFAULTfontname]\fi:}
+\ifx\FontNameToTable\empty \let\FontNameToTable\DEFAULTfontname \fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+\typein[\IsUnicodeFont]%
+ {^^JIs this a Unicode font?^^J^^J%
+ \ifx\DEFAULTunicodefont\empty [default yes]\else [default no]\fi:}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ifx\IsUnicodeFont\empty
+% \ifx\DEFAULTunicodefont\empty
+% \else
+ \let\IsUnicodeFont\DEFAULTunicodefont
+% \fi
+\else
+ \ifx\DEFAULTunicodefont\empty
+ \else
+ \let\IsUnicodeFont\empty
+ \fi
+\fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ifx\IsUnicodeFont\empty
+ \typein[\FontFeaturesToApply]%
+ {^^JInput font feature key/value list to apply%
+ \ifx\DEFAULTfontfeatures\empty\else
+ ^^J^^J[default \DEFAULTfontfeatures]\fi:}
+ \ifx\FontFeaturesToApply\empty \let\FontFeaturesToApply\DEFAULTfontfeatures \fi
+\else
+ \let\FontFeaturesToApply\DEFAULTfontfeatures
+\fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+\typein[\TableConfigurationToApply]%
+ {^^JInput table configuration key/value list to apply%
+ \ifx\DEFAULTtableconfig\empty\else
+ ^^J^^J[default
+ \expandafter\detokenize\expandafter{\DEFAULTtableconfig}]\fi:}
+\ifx\TableConfigurationToApply\empty
+ \let\TableConfigurationToApply\DEFAULTtableconfig
+\fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+\edef\generatetable{\noexpand\displayfonttable
+ \ifx\IsUnicodeFont\empty\else *\fi
+ \ifx\TableConfigurationToApply\empty\else
+ [\expandafter\unexpanded\expandafter{\TableConfigurationToApply}]\fi
+ {\FontNameToTable}%
+ \ifx\FontFeaturesToApply\empty\else[\FontFeaturesToApply]\fi
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\fi
+% \end{macrocode}
+%
+% \begin{macrocode}
+\makeatletter
+\protected@write\@auxout{}{\gdef\string\generatetable
+ {\expandafter\detokenize\expandafter{\generatetable}}}
+\protected@write\@auxout{}{\gdef\string\DEFAULTfontname{\FontNameToTable}}
+\protected@write\@auxout{}{\gdef\string\DEFAULTunicodefont{\IsUnicodeFont}}
+\protected@write\@auxout{}{\gdef\string\DEFAULTfontfeatures{\FontFeaturesToApply}}
+\protected@write\@auxout{}{\gdef\string\DEFAULTtableconfig
+ {\expandafter\detokenize\expandafter{\TableConfigurationToApply}}}
+\makeatother
+% \end{macrocode}
+%
+% \begin{macrocode}
+\generatetable
+\end{document}
+%</standalone>
+% \end{macrocode}
+%
+%
+%
+% \section{A samples file}
+%
+% \begin{macrocode}
+%<*samples>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<<VERBATIMLINE
+%!TEX program = lualatex
+
+%VERBATIMLINE
+% \end{macrocode}
+%
+% \begin{macrocode}
+\documentclass{article}
+
+\usepackage{xparse,color}
+
+\usepackage{fontspec}
+
+\setmainfont{Linux Biolinum O}
+\setmonofont{SourceCodePro}
+
+\usepackage{unicodefonttable}
+
+\addtolength\textwidth{30pt}
+
+\begin{document}
+
+\listoftables
+
+\section{Computer Modern --- 8bit font}
+
+\displayfonttable*[color=none,
+ range-end = 7F,
+]{cmr10}
+
+%\section{Computer Modern Sans --- 8bit font} \displayfonttable*[]{cmss10}
+
+\newpage
+
+\section{TeX Gyre Heros (Helvetica) --- 8bit font}
+
+\displayfonttable*[color=red,nostatistics=false,
+ hex-digits = head+foot,
+ range-end = FF,
+]{ec-qhvr}
+
+\newpage
+
+\section{Latin Modern Sans --- OTF font}
+
+\displayfonttable[
+% display-block = rules,
+ % missing-glyph = \tiny\setlength\fboxsep{0pt}\fbox{$\times$},
+ hex-digits = block,
+ title-cont-format = \caption[]{\emph{continued}},
+]{Latin Modern Sans}
+
+\newpage
+
+\section{\TeX{} Gyre Pagella (Palatino) oldstyle figures --- OTF font}
+
+\displayfonttable{TeX Gyre Pagella}[Numbers=OldStyle]
+
+\newpage
+
+\section{Comparing Latin Modern Math with New Computer Modern Math}
+
+\displayfonttable[compare-with=NewCMMath-Regular.otf, range-end=1FFFF]
+ {latinmodern-math.otf}
+
+\end{document}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</samples>
+% \end{macrocode}
+%
+% \Finale
+%
+
+
+\endinput
+
+%%%%%%%%%%%%%%%%%%%
diff --git a/Master/texmf-dist/source/latex/unicodefonttable/unicodefonttable.ins b/Master/texmf-dist/source/latex/unicodefonttable/unicodefonttable.ins
new file mode 100644
index 00000000000..b87cb4e13f4
--- /dev/null
+++ b/Master/texmf-dist/source/latex/unicodefonttable/unicodefonttable.ins
@@ -0,0 +1,72 @@
+%%
+%% This file will generate fast loadable files and documentation
+%% driver files from the dtx file(s) in this package when run through
+%% LaTeX or TeX.
+%%
+%% Copyright 2019-2021 Frank Mittelbach
+%%
+%%
+%% This file is part of the unicodefonttable Bundle for LaTeX.
+%% -------------------------------------------------------
+%%
+%% It may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either version 1.3c
+%% of this license or (at your option) any later version.
+%% The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt
+%% and version 1.3c or later is part of all distributions of LaTeX
+%% version 2008 or later.
+%%
+%% As this file contains legal notices, it is NOT PERMITTED to modify
+%% this file in any way that the legal information placed into
+%% generated files is changed (i.e., the files generated when the
+%% original file is executed). This restriction does not apply if
+%% (parts of) the content is reused in a different WORK producing its
+%% own generated files.
+%%
+%%
+%% --------------- start of docstrip commands ------------------
+%%
+\input docstrip
+
+\keepsilent
+\askforoverwritefalse
+
+\usedir{tex/latex/unicodefonttable}
+
+\preamble
+
+This is a generated file.
+
+Copyright 2019-2021 Frank Mittelbach
+
+This file was generated from file(s) of the LaTeX `unicodefonttable Bundle'.
+--------------------------------------------------------------------------
+
+It may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either version 1.3c
+of this license or (at your option) any later version.
+The latest version of this license is in
+ https://www.latex-project.org/lppl.txt
+and version 1.3c or later is part of all distributions of LaTeX
+version 2008 or later.
+
+This file may only be distributed together with a copy of the LaTeX
+`unicodefonttable Bundle'. You may however distribute the `unicodefonttable Bundle'
+without such generated files.
+
+The newest sources can be found below
+
+ https://github.com/FrankMittelbach/fmitex-unicodetable
+
+where one can also log issues in case there are any.
+
+
+\endpreamble
+
+\generate{\file{unicodefonttable.sty}{\from{unicodefonttable.dtx}{package}}}
+\generate{\file{unicodefonttable-samples.tex}{\from{unicodefonttable.dtx}{samples}}}
+
+\generate{\file{unicodefont.tex}{\from{unicodefonttable.dtx}{standalone}}}
+
+\endbatchfile
diff --git a/Master/texmf-dist/tex/latex/unicodefonttable/unicodefont.tex b/Master/texmf-dist/tex/latex/unicodefonttable/unicodefont.tex
new file mode 100644
index 00000000000..309f1eb1b9b
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/unicodefonttable/unicodefont.tex
@@ -0,0 +1,125 @@
+%%
+%% This is file `unicodefont.tex',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% unicodefonttable.dtx (with options: `standalone')
+%%
+%% This is a generated file.
+%%
+%% Copyright 2019-2021 Frank Mittelbach
+%%
+%% This file was generated from file(s) of the LaTeX `unicodefonttable Bundle'.
+%% --------------------------------------------------------------------------
+%%
+%% It may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either version 1.3c
+%% of this license or (at your option) any later version.
+%% The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt
+%% and version 1.3c or later is part of all distributions of LaTeX
+%% version 2008 or later.
+%%
+%% This file may only be distributed together with a copy of the LaTeX
+%% `unicodefonttable Bundle'. You may however distribute the `unicodefonttable Bundle'
+%% without such generated files.
+%%
+%% The newest sources can be found below
+%%
+%% https://github.com/FrankMittelbach/fmitex-unicodetable
+%%
+%% where one can also log issues in case there are any.
+%%
+%%
+%%%%% \iffalse meta-comment
+%% File: unicodefonttable.dtx (C) Copyright 2019-2021 Frank Mittelbach
+
+\def\unicodefonttabledate {2021/10/19}
+\def\unicodefonttableversion{v1.0e}
+
+
+\documentclass{article}
+\setlength\textwidth{470pt}
+\setlength\oddsidemargin{0pt}
+\addtolength\textheight{7\baselineskip}
+\addtolength\topmargin{-3\baselineskip}
+\usepackage{unicodefonttable}
+\def\DEFAULTfontname{Latin Modern Roman}
+\def\DEFAULTfontfeatures{}
+\def\DEFAULTtableconfig{}
+\def\DEFAULTunicodefont{}
+\begin{document}
+\typeout{^^J}
+\ifx\generatetable\undefined
+\else
+ \typein[\answer]{^^JReuse settings from last time (default yes)?^^J^^J%
+ [ font name = \DEFAULTfontname^^J
+ \space unicode? = \ifx\DEFAULTunicodefont\empty yes^^J
+ \space font features = \DEFAULTfontfeatures
+ \else no\fi^^J
+ \space table config = \DEFAULTtableconfig \space]}
+\fi
+\ifx\answer\empty
+ \let\FontNameToTable\DEFAULTfontname
+ \let\IsUnicodeFont\DEFAULTunicodefont
+ \let\FontFeaturesToApply\DEFAULTfontfeatures
+ \let\TableConfigurationToApply\DEFAULTtableconfig
+\else
+\typein[\FontNameToTable]%
+ {^^JInput external font name as understood by fontspec, e.g.,^^J%
+ 'TeX Gyre Pagella' or 'lmroman10-regular.otf'%
+ \ifx\DEFAULTfontname\empty\else
+ ^^J^^J[default \DEFAULTfontname]\fi:}
+\ifx\FontNameToTable\empty \let\FontNameToTable\DEFAULTfontname \fi
+\typein[\IsUnicodeFont]%
+ {^^JIs this a Unicode font?^^J^^J%
+ \ifx\DEFAULTunicodefont\empty [default yes]\else [default no]\fi:}
+\ifx\IsUnicodeFont\empty
+ \let\IsUnicodeFont\DEFAULTunicodefont
+\else
+ \ifx\DEFAULTunicodefont\empty
+ \else
+ \let\IsUnicodeFont\empty
+ \fi
+\fi
+\ifx\IsUnicodeFont\empty
+ \typein[\FontFeaturesToApply]%
+ {^^JInput font feature key/value list to apply%
+ \ifx\DEFAULTfontfeatures\empty\else
+ ^^J^^J[default \DEFAULTfontfeatures]\fi:}
+ \ifx\FontFeaturesToApply\empty \let\FontFeaturesToApply\DEFAULTfontfeatures \fi
+\else
+ \let\FontFeaturesToApply\DEFAULTfontfeatures
+\fi
+\typein[\TableConfigurationToApply]%
+ {^^JInput table configuration key/value list to apply%
+ \ifx\DEFAULTtableconfig\empty\else
+ ^^J^^J[default
+ \expandafter\detokenize\expandafter{\DEFAULTtableconfig}]\fi:}
+\ifx\TableConfigurationToApply\empty
+ \let\TableConfigurationToApply\DEFAULTtableconfig
+\fi
+\edef\generatetable{\noexpand\displayfonttable
+ \ifx\IsUnicodeFont\empty\else *\fi
+ \ifx\TableConfigurationToApply\empty\else
+ [\expandafter\unexpanded\expandafter{\TableConfigurationToApply}]\fi
+ {\FontNameToTable}%
+ \ifx\FontFeaturesToApply\empty\else[\FontFeaturesToApply]\fi
+}
+\fi
+\makeatletter
+\protected@write\@auxout{}{\gdef\string\generatetable
+ {\expandafter\detokenize\expandafter{\generatetable}}}
+\protected@write\@auxout{}{\gdef\string\DEFAULTfontname{\FontNameToTable}}
+\protected@write\@auxout{}{\gdef\string\DEFAULTunicodefont{\IsUnicodeFont}}
+\protected@write\@auxout{}{\gdef\string\DEFAULTfontfeatures{\FontFeaturesToApply}}
+\protected@write\@auxout{}{\gdef\string\DEFAULTtableconfig
+ {\expandafter\detokenize\expandafter{\TableConfigurationToApply}}}
+\makeatother
+\generatetable
+\end{document}
+
+\endinput
+%%
+%% End of file `unicodefont.tex'.
diff --git a/Master/texmf-dist/tex/latex/unicodefonttable/unicodefonttable.sty b/Master/texmf-dist/tex/latex/unicodefonttable/unicodefonttable.sty
new file mode 100644
index 00000000000..fb4df406402
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/unicodefonttable/unicodefonttable.sty
@@ -0,0 +1,725 @@
+%%
+%% This is file `unicodefonttable.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% unicodefonttable.dtx (with options: `package')
+%%
+%% This is a generated file.
+%%
+%% Copyright 2019-2021 Frank Mittelbach
+%%
+%% This file was generated from file(s) of the LaTeX `unicodefonttable Bundle'.
+%% --------------------------------------------------------------------------
+%%
+%% It may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either version 1.3c
+%% of this license or (at your option) any later version.
+%% The latest version of this license is in
+%% https://www.latex-project.org/lppl.txt
+%% and version 1.3c or later is part of all distributions of LaTeX
+%% version 2008 or later.
+%%
+%% This file may only be distributed together with a copy of the LaTeX
+%% `unicodefonttable Bundle'. You may however distribute the `unicodefonttable Bundle'
+%% without such generated files.
+%%
+%% The newest sources can be found below
+%%
+%% https://github.com/FrankMittelbach/fmitex-unicodetable
+%%
+%% where one can also log issues in case there are any.
+%%
+%%
+%%%%% \iffalse meta-comment
+%% File: unicodefonttable.dtx (C) Copyright 2019-2021 Frank Mittelbach
+
+\def\unicodefonttabledate {2021/10/19}
+\def\unicodefonttableversion{v1.0e}
+
+
+\RequirePackage{xcolor}
+
+\RequirePackage{xparse,l3keys2e}
+\ProvidesExplPackage{unicodefonttable}
+ {\unicodefonttabledate}
+ {\unicodefonttableversion}
+ {Producing font tables for Unicode and other fonts}
+
+\NewDocumentCommand \fonttablesetup { m }
+ { \keys_set:nn {__fmuft} {#1} \ignorespaces }
+\NewDocumentCommand\displayfonttable {s O{} m o}{%
+ \IfBooleanTF #1
+ {
+ \__fmuft_display_fonttable:nnn
+ {nostatistics,display-block=none,hex-digits=head,range-end=FF,#2}
+ {#3}{#4}
+ }
+ {
+ \__fmuft_display_fonttable:nnn {#2}{#3}{#4}
+ }
+}
+\cs_new:Npn \__fmuft_display_fonttable:nnn #1#2#3 {
+ \group_begin:
+ \fontspec{#2}[#3]
+ \keys_set:nn{__fmuft}{#1}
+ \tl_if_empty:NTF \l__fmuft_compare_with_tl
+ { \tl_clear:N \l__fmuft_compare_font_tl }
+ {
+ \setfontface \l__fmuft_compare_font_tl {\l__fmuft_compare_with_tl}[]
+ \cs_set_eq:NN \__fmuft_handle_missing_glyph:n
+ \__fmuft_handle_missing_glyph_compare:n
+ }
+ \begin{longtable\bool_if:NF\l__fmuft_display_header_bool{*}}
+ {@{}r@{\quad}*{16}{c}@{}}
+ \__fmuft_setup_header_footer:nn{#2}{#3}
+ \__fmuft_produce_table_rows:
+ \__fmuft_handle_table_ending:n {#2}
+ \end{longtable\bool_if:NF\l__fmuft_display_header_bool{*}}
+ \group_end:
+}
+
+\DeclareDocumentCommand \fonttableglyphcount {}
+ { \int_use:N \g__fmuft_glyph_int }
+\int_new:N \g__fmuft_glyph_int
+\int_new:N \g__fmuft_glyph_only_B_int
+\int_new:N \g__fmuft_glyph_also_B_int
+
+\cs_new:Npn \__fmuft_setup_header_footer:nn #1#2{
+ \bool_if:NT \l__fmuft_display_header_bool
+ { \__fmuft_format_table_title:nn{#1}{#2} \__fmuft_debug_nl:n{T}\\*[6pt] }
+ \bool_if:NT \l__fmuft_header_hex_digits_bool
+ { \__fmuft_display_row_of_hex_digits: \__fmuft_debug_nl:n{H}\\* }
+ \endfirsthead
+ \bool_if:NT \l__fmuft_display_header_bool
+ { \__fmuft_format_table_cont:nn{#1}{#2} \__fmuft_debug_nl:n{T}\\*[6pt] }
+ \bool_if:NT \l__fmuft_header_hex_digits_bool
+ { \__fmuft_display_row_of_hex_digits: \__fmuft_debug_nl:n{H}\\* }
+ \endhead
+ \bool_if:NT \l__fmuft_footer_hex_digits_bool
+ { \__fmuft_display_row_of_hex_digits: \__fmuft_debug_nl:n{H}\\* }
+ \endfoot
+ \endlastfoot
+}
+\bool_new:N \l__fmuft_header_hex_digits_bool
+\bool_new:N \l__fmuft_footer_hex_digits_bool
+\bool_new:N \l__fmuft_blockwise_hex_digits_bool
+\cs_new:Npn \__fmuft_display_row_of_hex_digits: {
+ & \__fmuft_format_hex_digit:n{0} & \__fmuft_format_hex_digit:n{1}
+ & \__fmuft_format_hex_digit:n{2} & \__fmuft_format_hex_digit:n{3}
+ & \__fmuft_format_hex_digit:n{4} & \__fmuft_format_hex_digit:n{5}
+ & \__fmuft_format_hex_digit:n{6} & \__fmuft_format_hex_digit:n{7}
+ & \__fmuft_format_hex_digit:n{8} & \__fmuft_format_hex_digit:n{9}
+ & \__fmuft_format_hex_digit:n{A} & \__fmuft_format_hex_digit:n{B}
+ & \__fmuft_format_hex_digit:n{C} & \__fmuft_format_hex_digit:n{D}
+ & \__fmuft_format_hex_digit:n{E} & \__fmuft_format_hex_digit:n{F} }
+\cs_new:Npn \__fmuft_format_hex_digit:n #1 {
+ \l__fmuft_hex_digits_font_tl \l__fmuft_color_tl #1 }
+
+\tl_new:N \l__fmuft_color_tl
+\keys_define:nn {__fmuft} {
+ ,header .bool_set:N = \l__fmuft_display_header_bool
+ ,header .default:n = true
+ ,header .initial:n = true
+ ,noheader .bool_set_inverse:N = \l__fmuft_display_header_bool
+ ,noheader .default:n = true
+ ,title-format .cs_set:Np = \__fmuft_format_table_title:nn #1#2
+ ,title-format .initial:n =
+ \IfValueTF{#2} { \caption{ #1~ (features:~ \texttt{\small#2}) } }
+ { \caption{ #1 } }
+ ,title-cont-format .cs_set:Np = \__fmuft_format_table_cont:nn #1#2
+ ,title-cont-format .initial:n = \caption[]{#1~ \emph{cont.}}
+ ,hex-digits .choice:
+ ,hex-digits / block .code:n =
+ \bool_set_true:N \l__fmuft_blockwise_hex_digits_bool
+ \bool_set_false:N \l__fmuft_header_hex_digits_bool
+ \bool_set_false:N \l__fmuft_footer_hex_digits_bool
+ ,hex-digits / foot .code:n =
+ \bool_set_true:N \l__fmuft_footer_hex_digits_bool
+ \bool_set_false:N \l__fmuft_header_hex_digits_bool
+ \bool_set_false:N \l__fmuft_blockwise_hex_digits_bool
+ ,hex-digits / head .code:n =
+ \bool_set_true:N \l__fmuft_header_hex_digits_bool
+ \bool_set_false:N \l__fmuft_footer_hex_digits_bool
+ \bool_set_false:N \l__fmuft_blockwise_hex_digits_bool
+ ,hex-digits / head+foot .code:n =
+ \bool_set_true:N \l__fmuft_header_hex_digits_bool
+ \bool_set_true:N \l__fmuft_footer_hex_digits_bool
+ \bool_set_false:N \l__fmuft_blockwise_hex_digits_bool
+ ,hex-digits / none .code:n =
+ \bool_set_false:N \l__fmuft_header_hex_digits_bool
+ \bool_set_false:N \l__fmuft_footer_hex_digits_bool
+ \bool_set_false:N \l__fmuft_blockwise_hex_digits_bool
+ ,hex-digits .initial:n = head
+ ,hex-digits-font .tl_set:N = \l__fmuft_hex_digits_font_tl
+ ,hex-digits-font .initial:n = \ttfamily \scriptsize
+ ,color .choice:
+ ,color / none .code:n = \tl_clear:N \l__fmuft_color_tl
+ ,color / unknown .code:n = \tl_set:Nn \l__fmuft_color_tl { \color {#1} }
+ ,color .initial:n = blue
+ }
+\cs_new:Npn \__fmuft_handle_table_ending:n #1 {
+ \__fmuft_debug_nl:n{H} \\*
+ \bool_if:NT \l__fmuft_footer_hex_digits_bool
+ { \__fmuft_display_row_of_hex_digits: \__fmuft_debug_nl:n{H} \\* }
+ \bool_if:NT \l__fmuft_display_statistics_bool
+ { \\*[2pt]
+ \multicolumn{17}{l}{ \l__fmuft_stats_font_tl
+ \tl_if_empty:NTF \l__fmuft_compare_with_tl
+ {
+ \__fmuft_format_stats:nn{#1}{\fonttableglyphcount}
+ }
+ {
+ \__fmuft_format_compare_stats:nnnnnn{#1}{\fonttableglyphcount}
+ { \l__fmuft_compare_with_tl }
+ { \int_eval:n { \int_use:N\g__fmuft_glyph_also_B_int +
+ \int_use:N\g__fmuft_glyph_only_B_int }
+ }
+ { \int_eval:n { \fonttableglyphcount -
+ \int_use:N\g__fmuft_glyph_also_B_int }
+ }
+ { \int_use:N\g__fmuft_glyph_only_B_int }
+ }
+ \hspace*{-3cm}
+ }
+ }
+}
+\keys_define:nn {__fmuft} {
+ ,statistics .bool_set:N = \l__fmuft_display_statistics_bool
+ ,statistics .default:n = true
+ ,statistics .initial:n = true
+ ,nostatistics .bool_set_inverse:N = \l__fmuft_display_statistics_bool
+ ,nostatistics .default:n = true
+ ,statistics-font .tl_set:N = \l__fmuft_stats_font_tl
+ ,statistics-font .initial:n = \normalfont\small
+ ,statistics-format .cs_set:Np = \__fmuft_format_stats:nn #1#2
+ ,statistics-format .initial:n = Total~ number~ of~ glyphs~ in~ #1:~#2
+ }
+\cs_new:Npn \__fmuft_debug_nl:n #1 {}
+\keys_define:nn {__fmuft} {
+ debug .code:n = \cs_set:Npn \__fmuft_debug_nl:n ##1
+ {\rlap{\normalfont\scriptsize \qquad ##1}} }
+
+\tl_new:N \g__fmuft_hex_H_tl % higher plane
+\tl_new:N \g__fmuft_hex_A_tl
+\tl_new:N \g__fmuft_hex_B_tl
+\tl_new:N \g__fmuft_hex_C_tl
+\clist_const:Nn\c__fmuft_hex_digits_clist{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F}
+\cs_new:Npn \__fmuft_produce_table_rows: {
+ \__fmuft_initialize_table_rows:
+ \clist_map_function:nN { { } , 1, 2, E, F } \__fmuft_handle_hex_H:n }
+\cs_new:Npn \__fmuft_handle_hex_H:n #1 { \tl_gset:Nn\g__fmuft_hex_H_tl{#1}
+ \clist_map_function:NN \c__fmuft_hex_digits_clist \__fmuft_handle_hex_A:n }
+\cs_new:Npn \__fmuft_handle_hex_A:n #1 { \tl_gset:Nn\g__fmuft_hex_A_tl{#1}
+ \clist_map_function:NN \c__fmuft_hex_digits_clist \__fmuft_handle_hex_B:n }
+\cs_new:Npn \__fmuft_handle_hex_B:n #1 { \tl_gset:Nn\g__fmuft_hex_B_tl{#1}
+ \clist_map_function:NN \c__fmuft_hex_digits_clist \__fmuft_handle_hex_C:n }
+\cs_new:Npn \__fmuft_handle_hex_C:n #1 { \tl_gset:Nn\g__fmuft_hex_C_tl{#1}
+ \clist_map_function:NN \c__fmuft_hex_digits_clist \__fmuft_handle_hex_D:n }
+\cs_new:Npn \__fmuft_handle_hex_D:n #1 {
+ \__fmuft_handle_slot:x
+ { " \g__fmuft_hex_H_tl \g__fmuft_hex_A_tl
+ \g__fmuft_hex_B_tl \g__fmuft_hex_C_tl #1 }
+}
+\tl_new:N \g__fmuft_row_tl
+
+\cs_new:Npn \__fmuft_handle_slot:n #1 {
+ \__fmuft_if_uchar_exists:nTF { #1 }
+ { \tl_gput_right:Nn \g__fmuft_row_tl
+ { & \__fmuft_format_glyph:n { \symbol{#1} } }
+ \int_gincr:N\g__fmuft_glyph_int
+ \bool_gset_true:N \g__fmuft_glyph_seen_bool
+ \tl_if_empty:NF \l__fmuft_compare_font_tl
+ {
+ \group_begin:
+ \l__fmuft_compare_font_tl
+ \__fmuft_if_uchar_exists:nT { #1 }
+ { \int_gincr:N \g__fmuft_glyph_also_B_int }
+ \group_end:
+ }
+ }
+ { \__fmuft_handle_missing_glyph:n {#1} }
+}
+\cs_generate_variant:Nn \__fmuft_handle_slot:n {x}
+
+\cs_new:Npn \__fmuft_handle_missing_glyph_std:n #1 {
+ \tl_gput_right:Nn \g__fmuft_row_tl
+ { &
+ \__fmuft_format_glyph:n {
+ {\l__fmuft_missing_glyph_color_tl
+ \l__fmuft_missing_glyph_font_tl
+ \l__fmuft_missing_glyph_tl }
+ }
+ }
+}
+\keys_define:nn {__fmuft} {
+ missing-glyph-color .choice:
+ ,missing-glyph-color / none .code:n =
+ \tl_clear:N \l__fmuft_missing_glyph_color_tl
+ ,missing-glyph-color / unknown .code:n =
+ \tl_set:Nn \l__fmuft_missing_glyph_color_tl { \color {#1} }
+ ,missing-glyph-font .tl_set:N = \l__fmuft_missing_glyph_font_tl
+ ,missing-glyph-font .initial:n = \ttfamily \scriptsize
+ ,missing-glyph .tl_set:N = \l__fmuft_missing_glyph_tl
+ ,missing-glyph .initial:n = - }
+\tl_new:N \l__fmuft_missing_glyph_color_tl
+\tl_set:Nn \l__fmuft_missing_glyph_color_tl {\l__fmuft_color_tl}
+\cs_new:Npn \__fmuft_handle_missing_glyph_compare:n #1 {
+ \group_begin:
+ \l__fmuft_compare_font_tl
+ \__fmuft_if_uchar_exists:nTF { #1 }
+ {
+ \tl_gput_right:Nn \g__fmuft_row_tl
+ { &
+ \__fmuft_format_glyph:n
+ { \l__fmuft_compare_bgcolor_tl { \l__fmuft_compare_color_tl
+ \l__fmuft_compare_font_tl
+ \symbol {#1} }
+ }
+ }
+ \int_gincr:N \g__fmuft_glyph_only_B_int
+ \bool_gset_true:N \g__fmuft_glyph_seen_bool
+ }
+ { \__fmuft_handle_missing_glyph_std:n {} }
+ \group_end:
+}
+\tl_new:N \l__fmuft_compare_with_tl
+\tl_new:N \l__fmuft_compare_color_tl
+\tl_new:N \l__fmuft_compare_bgcolor_tl
+\keys_define:nn {__fmuft}
+ {
+ ,compare-with .tl_set:N = \l__fmuft_compare_with_tl
+ ,compare-with .initial:n =
+ ,compare-color .choice:
+ ,compare-color / none .code:n
+ = \tl_clear:N \l__fmuft_compare_color_tl
+ ,compare-color / unknown .code:n
+ = \tl_set:Nn \l__fmuft_compare_color_tl { \color {#1} }
+ ,compare-color .initial:n = red
+ ,compare-bgcolor .choice:
+ ,compare-bgcolor / none .code:n
+ = \tl_clear:N \l__fmuft_compare_bgcolor_tl
+ ,compare-bgcolor / unknown .code:n
+ = \tl_set:Nn \l__fmuft_compare_bgcolor_tl { \colorbox {#1} }
+ ,compare-bgcolor .initial:n = black!10
+ ,statistics-compare-format .cs_set:Np
+ = \__fmuft_format_compare_stats:nnnnnn #1#2#3#4#5#6
+ ,statistics-compare-format .initial:n
+ = \parbox{\linewidth}{
+ Total~ number~ of~ glyphs~ in~ \texttt{#1}:~#2\\
+ Comparison~ font~ \texttt{#3}~ has~ #5~ missing~ and~ #6~
+ extra~ glyphs}
+ }
+\cs_new_eq:NN \__fmuft_handle_missing_glyph:n
+ \__fmuft_handle_missing_glyph_std:n
+
+\cs_new:Npn \__fmuft_format_glyph:n #1 {
+ \hbox_to_wd:nn {\l__fmuft_glyph_box_dim} { \hss #1 \hss } }
+\dim_new:N\l__fmuft_glyph_box_dim
+\keys_define:nn {__fmuft} {
+ glyph-width .dim_set:N = \l__fmuft_glyph_box_dim
+ ,glyph-width .initial:n = 6pt
+}
+
+\prg_set_conditional:Npnn \__fmuft_if_uchar_exists:n #1 { TF , T }
+ { \tex_iffontchar:D \tex_font:D #1 \scan_stop:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\cs_set:Npn \__fmuft_handle_hex_C:n #1 {
+ \__fmuft_maybe_typeset_a_row_and_display_a_block_title:
+ \tl_gset:Nn\g__fmuft_hex_C_tl{#1}
+ \__fmuft_update_block_title:n { \g__fmuft_hex_H_tl
+ \g__fmuft_hex_A_tl
+ \g__fmuft_hex_B_tl
+ \g__fmuft_hex_C_tl }
+ \int_compare:nNnF
+ { " \g__fmuft_hex_H_tl \g__fmuft_hex_A_tl
+ \g__fmuft_hex_B_tl \g__fmuft_hex_C_tl 0 }
+ < { "\l__fmuft_range_start_tl }
+ {
+ \int_compare:nNnTF
+ { " \g__fmuft_hex_H_tl \g__fmuft_hex_A_tl
+ \g__fmuft_hex_B_tl \g__fmuft_hex_C_tl 0 }
+ > { "\l__fmuft_range_end_tl }
+ { \clist_map_break: }
+ {
+ \tl_gset:Nx \g__fmuft_row_tl
+ {
+ \exp_not:N \__fmuft_format_row_title:n
+ { \g__fmuft_hex_H_tl \g__fmuft_hex_A_tl
+ \g__fmuft_hex_B_tl \g__fmuft_hex_C_tl }
+ }
+ \clist_map_function:NN \c__fmuft_hex_digits_clist
+ \__fmuft_handle_hex_D:n
+ }
+ }
+}
+\cs_new:Npn \__fmuft_format_row_title:n #1 {
+ \texttt { \footnotesize \l__fmuft_color_tl U+#1 0 \, - \, #1 F }
+}
+\tl_new:N \l__fmuft_range_start_tl
+\tl_new:N \l__fmuft_range_end_tl
+\keys_define:nn {__fmuft}
+ {
+ ,range-start .tl_set:N = \l__fmuft_range_start_tl
+ ,range-start .initial:n = 0000
+ ,range-end .tl_set:N = \l__fmuft_range_end_tl
+ ,range-end .initial:n = FFFF
+ }
+\cs_new:Npn \__fmuft_maybe_typeset_a_row_and_display_a_block_title: {
+ \bool_if:NTF \g__fmuft_glyph_seen_bool
+ {
+ \tl_if_empty:NTF \g__fmuft_block_title_tl
+ {
+ \bool_if:NTF \g__fmuft_row_missing_bool
+ { \__fmuft_debug_nl:n{A}\\[6pt] }
+ { \__fmuft_debug_nl:n{B}\\ }
+ }
+ {
+ \typeout{ Processing~ \tl_use:N \g__fmuft_block_title_tl }
+ \bool_if:NTF \l__fmuft_display_block_bool
+ {
+ \bool_if:NTF \g__fmuft_first_row_bool
+ {
+ \bool_gset_false:N \g__fmuft_first_row_bool
+ \__fmuft_debug_nl:n{C}\\[-4pt]
+ }
+ {
+ \__fmuft_debug_nl:n{D}\\[8pt]
+ \noalign{\vskip 1pt plus 1pt} % space above block: customizable?
+ }
+ \multicolumn{17}{c}{\normalfont \bfseries
+ \tl_use:N \g__fmuft_block_title_tl}
+ \bool_if:NTF \l__fmuft_blockwise_hex_digits_bool
+ { \__fmuft_debug_nl:n{E}\\*
+ \__fmuft_display_row_of_hex_digits:
+ \__fmuft_debug_nl:n{H}\\*[2pt]
+ }
+ { \__fmuft_debug_nl:n{F}\\*[2pt] }
+ }
+ {
+ \bool_if:NTF \g__fmuft_first_row_bool
+ { \bool_gset_false:N \g__fmuft_first_row_bool }
+ {
+ \__fmuft_debug_nl:n{G~ (new~ block)}
+ \l__fmuft_display_block_action_tl
+ }
+ }
+ \tl_gclear:N \g__fmuft_block_title_tl
+ }
+ \bool_gset_false:N \g__fmuft_glyph_seen_bool
+ \bool_gset_false:N \g__fmuft_row_missing_bool
+ \tl_use:N \g__fmuft_row_tl
+ }
+ {
+ \bool_gset_true:N \g__fmuft_row_missing_bool
+ }
+}
+
+\bool_new:N \g__fmuft_first_row_bool
+\bool_new:N \g__fmuft_glyph_seen_bool
+\bool_new:N \g__fmuft_row_missing_bool
+
+\cs_new:Npn \__fmuft_initialize_table_rows: {
+ \bool_gset_true:N \g__fmuft_first_row_bool
+ \bool_gset_false:N \g__fmuft_glyph_seen_bool
+ \bool_gset_false:N \g__fmuft_row_missing_bool
+ \int_gzero:N \g__fmuft_glyph_int
+ \int_gzero:N \g__fmuft_glyph_only_B_int
+ \int_gzero:N \g__fmuft_glyph_also_B_int
+}
+
+\tl_new:N \g__fmuft_block_title_tl
+
+\cs_new:Npn \__fmuft_update_block_title:n #1 {
+ \tl_gset:Nx \g__fmuft_block_title_tl {
+ \int_case:nnF{ "#1 }
+ {
+ { "000 }{ Basic~ Latin }
+ { "008 }{ Latin-1~ Supplement }
+ { "010 }{ Latin~ Extended-A }
+ { "018 }{ Latin~ Extended-B }
+ { "025 }{ IPA~ Extensions }
+ { "02B }{ Spacing~ Modifier~ Letters }
+ { "030 }{ Combining~ Diacritical~ Marks }
+ { "037 }{ Greek~ and~ Coptic }
+ { "040 }{ Cyrillic }
+ { "053 }{ Armenian }
+ { "059 }{ Hebrew }
+ { "060 }{ Arabic }
+ { "070 }{ Syriac }
+ { "075 }{ Arabic~ Supplement }
+ { "078 }{ Thaana }
+ { "07C }{ NKo }
+ { "090 }{ Devanagari }
+ { "098 }{ Bengali }
+ { "0A0 }{ Gurmukhi }
+ { "0A8 }{ Gujarati }
+ { "0B0 }{ Oriya }
+ { "0B8 }{ Tamil }
+ { "0C0 }{ Telugu }
+ { "0C8 }{ Kannada }
+ { "0D0 }{ Malayalm }
+ { "0D8 }{ Sinhala }
+ { "0E0 }{ Thai }
+ { "0E8 }{ Lao }
+ { "0F0 }{ Tibetan }
+ { "100 }{ Myanmar }
+ { "10A }{ Georgian }
+ { "110 }{ Hangul~ Jamo }
+ { "120 }{ Ethiopic }
+ { "138 }{ Ethiopic~ Supplement }
+ { "13A }{ Cherokee }
+ { "140 }{ Unified~ Canadian~ Aboriginal~ Syllabics }
+ { "168 }{ Ogham }
+ { "16A }{ Runic }
+ { "170 }{ Tagalog }
+ { "172 }{ Hanunoo }
+ { "174 }{ Buhid }
+ { "176 }{ Tagbanwa }
+ { "178 }{ Khmer }
+ { "180 }{ Mongolian }
+ { "190 }{ Limbu }
+ { "195 }{ Tai~ Le }
+ { "198 }{ New~ Tai~ Le }
+ { "19E }{ Khmer~ Symbols }
+ { "1A0 }{ Buginese }
+ { "1B0 }{ Balinese }
+ { "1D0 }{ Phonetic~ Extensions }
+ { "1D8 }{ Phonetic~ Extensions~ Supplement }
+ { "1DC }{ Combining~ Diacritical~ Marks~ Supplement }
+ { "1E0 }{ Latin~ Extended~ Additional }
+ { "1F0 }{ Greek~ Extended }
+ { "200 }{ General~ Punctuation }
+ { "207 }{ Superscripts~ and~ Subscripts }
+ { "20A }{ Currency~ Symbols }
+ { "20D }{ Combining~ Diacritical~ Marks~ for~ Symbols }
+ { "210 }{ Letterlike~ Symbols }
+ { "215 }{ Number~ Forms }
+ { "219 }{ Arrows }
+ { "220 }{ Mathematical~ Operators }
+ { "230 }{ Miscellaneous~ Technical }
+ { "240 }{ Control~ Pictures }
+ { "244 }{ Optical~ Character~ Recognition }
+ { "246 }{ Enclosed~ Alphanumerics }
+ { "250 }{ Box~ Drawing }
+ { "258 }{ Block~ Elements }
+ { "25A }{ Geometric~ Shapes }
+ { "260 }{ Miscellaneous~ Shapes }
+ { "270 }{ Dingbats }
+ { "27C }{ Miscellaneous~ Mathematical~ Symbols-A }
+ { "27F }{ Supplemental~ Arrows-A }
+ { "280 }{ Braille~ Patterns }
+ { "290 }{ Supplemental~ Arrows-B }
+ { "298 }{ Miscellaneous~ Mathematical~ Symbols-B }
+ { "2A0 }{ Supplemental~ Mathematical~ Operators }
+ { "2B0 }{ Miscellaneous~ Symbols~ and~ Arrows }
+ { "2C0 }{ Glagolitic }
+ { "2C6 }{ Latin~ Extended-C }
+ { "2C8 }{ Coptic }
+ { "2D0 }{ Georgian~ Supplement }
+ { "2D3 }{ Tifinagh }
+ { "2D8 }{ Ethiopic~ Extended }
+ { "2E0 }{ Supplemental~ Punctuation }
+ { "2E8 }{ CJK~ Radicals~ Supplement }
+ { "2F0 }{ Kangxi~ Radicals }
+ { "2FF }{ Ideographic~ Description~ Characters }
+ { "300 }{ CJK~ Symbols~ and~ Punctuation }
+ { "304 }{ Hiragana }
+ { "30A }{ Katakana }
+ { "310 }{ Bopomofo }
+ { "313 }{ Hangul~ Compatibility~ Jamo }
+ { "319 }{ Kanbun }
+ { "31A }{ Bopomofo~ Extended }
+ { "31C }{ CJK~ Strokes }
+ { "31F }{ Katakana~ Phonetic~ Extensions }
+ { "320 }{ Enclosed~ CJK~ Letters~ and~ Months }
+ { "330 }{ CJK~ Compatibility }
+ { "4DC }{ Yijing~ Hexagram~ Symbols }
+ { "A00 }{ Yi~ Syllables }
+ { "A49 }{ Yi~ Radicals }
+ { "A70 }{ Modifier~ Tone~ Letters }
+ { "A72 }{ Latin~ Extended-D }
+ { "A80 }{ Syloti~ Nagri }
+ { "A84 }{ Phags-pa }
+ { "A88 }{ Saurashtra }
+ { "A8E }{ Devanagari Extended }
+ { "A90 }{ Kayah Li }
+ { "A93 }{ Rejang }
+ { "A96 }{ Hangul Jamo Extended-A }
+ { "A98 }{ Javanese }
+ { "A9E }{ Myanmar Extended-B }
+ { "AA0 }{ Cham }
+ { "AA6 }{ Myanmar Extended-A }
+ { "AA8 }{ Tai Viet }
+ { "AAE }{ Meetei Mayek Extensions }
+ { "AB0 }{ Ethiopic Extended-A }
+ { "AB3 }{ Latin Extended-E }
+ { "AB7 }{ Cherokee Supplement }
+ { "ABC }{ Meetei Mayek }
+ { "AC0 }{ Hangul Syllables }
+ { "D7B }{ Hangul Jamo Extended-B }
+ { "D80 }{ High Surrogates }
+ { "DB8 }{ High Private Use Surrogates }
+ { "DC0 }{ Low Surrogates }
+ { "E00 }{ Private~ Use~ Area }
+ { "F90 }{ CJK~ Compatibility~ Ideographs }
+ { "FB0 }{ Alphabetic~ Presentation~ Forms }
+ { "FB5 }{ Arabic~ Presentation~ Forms-A }
+ { "FE0 }{ Variation~ Selectors }
+ { "FE1 }{ Vertical~ Forms }
+ { "FE2 }{ Combining~ Half~ Marks }
+ { "FE3 }{ CJK~ Compatibility~ Forms }
+ { "FE5 }{ Small~ Form~ Variants }
+ { "FE7 }{ Arabic~ Presentation~ Forms-B }
+ { "FF0 }{ Halfwidth~ and Fullwidth~ Forms }
+ { "FFF }{ Specials~ ... }
+%% ... Plane 1 ...
+ { "1000 }{ Linear~ B~ Syllabary }
+ { "1008 }{ Linear~ B~ Ideograms }
+ { "1010 }{ Aegean~ Numbers }
+ { "1014 }{ Ancient~ Greek~ Numbers }
+ { "1019 }{ Ancient~ Symbols }
+ { "101D }{ Phaistos~ Disc }
+ { "1028 }{ Lycian }
+ { "102A }{ Carian }
+ { "102E }{ Coptic~ Epact~ Numbers }
+ { "1030 }{ Old~ Italic }
+ { "1033 }{ Gothic }
+ { "1035 }{ Old~ Permic }
+ { "1038 }{ Ugaritic }
+ { "103A }{ Old~ Persian }
+ { "1040 }{ Deseret }
+ { "1045 }{ Shavian }
+ { "1048 }{ Osmanya }
+ { "104B }{ Osage }
+ { "1050 }{ Elbasan }
+ { "1053 }{ Caucasian~ Albanian }
+ { "1060 }{ Linear~ A }
+ { "1080 }{ Cypriot~ Syllabary }
+ { "1084 }{ Imperial~ Aramaic }
+ { "1086 }{ Palmyrene }
+ { "1088 }{ Nabataean }
+ { "108E }{ Hatran }
+ { "1090 }{ Phoenician }
+ { "1092 }{ Lydian }
+ { "1098 }{ Meroitic~ Hieroglyphs }
+ { "109A }{ Meroitic~ Cursive }
+ { "10A0 }{ Kharoshthi }
+ { "10A6 }{ Old~ South~ Arabian }
+ { "10A8 }{ Old~ North~ Arabian }
+ { "10AC }{ Manichaean }
+ { "10B0 }{ Avestan }
+ { "10B4 }{ Inscriptional~ Parthian }
+ { "10B6 }{ Inscriptional~ Pahlavi }
+ { "10B8 }{ Psalter~ Pahlavi }
+ { "10C0 }{ Old~ Turkic }
+ { "10C8 }{ Old~ Hungarian }
+ { "10E6 }{ Rumi~ Numeral~ Symbols }
+ { "1100 }{ Brahmi }
+ { "1108 }{ Kaithi }
+ { "110D }{ Sora~ Sompeng }
+ { "1110 }{ Chakma }
+ { "1115 }{ Mahajani }
+ { "1118 }{ Sharada }
+ { "111E }{ Sinhala~ Archaic~ Numbers }
+ { "1120 }{ Khojki }
+ { "1128 }{ Multani }
+ { "112B }{ Khudawadi }
+ { "1130 }{ Grantha }
+ { "1140 }{ Newa }
+ { "1148 }{ Tirhuta }
+ { "1158 }{ Siddham }
+ { "1160 }{ Modi }
+ { "1166 }{ Mongolian~ Supplement }
+ { "1168 }{ Takri }
+ { "1170 }{ Ahom }
+ { "118A }{ Warang~ Citi }
+ { "11A0 }{ Zanabazar~ Square }
+ { "11A5 }{ Soyombo }
+ { "11AC }{ Pau~ Cin~ Hau }
+ { "11C0 }{ Bhaiksuki }
+ { "11C7 }{ Marchen }
+ { "11D0 }{ Masaram~ Gondi }
+ { "1200 }{ Cuneiform }
+ { "1240 }{ Cuneiform~ Numbers~ and~ Punctuation }
+ { "1248 }{ Early~ Dynastic~ Cuneiform }
+ { "1300 }{ Egyptian~ Hieroglyphs }
+ { "1440 }{ Anatolian~ Hieroglyphs }
+ { "1680 }{ Bamum~ Supplement }
+ { "16A4 }{ Mro }
+ { "16AD }{ Bassa~ Vah }
+ { "16B0 }{ Pahawh~ Hmong }
+ { "16F0 }{ Miao }
+ { "16FE }{ Ideographic~ Symbols~ and~ Punctuation }
+ { "1700 }{ Tangut }
+ { "1880 }{ Tangut~ Components }
+ { "1B00 }{ Kana~ Supplement }
+ { "1B10 }{ Kana~ Extended-A }
+ { "1B17 }{ Nushu }
+ { "1BC0 }{ Duployan }
+ { "1BCA }{ Shorthand~ Format~ Controls }
+ { "1D00 }{ Byzantine~ Musical~ Symbols }
+ { "1D10 }{ Musical~ Symbols }
+ { "1D20 }{ Ancient~ Greek~ Musical~ Notation }
+ { "1D30 }{ Tai~ Xuan~ Jing~ Symbols }
+ { "1D36 }{ Counting~ Rod~ Numerals }
+ { "1D40 }{ Mathematical~ Alphanumeric~ Symbols }
+ { "1D80 }{ Sutton~ SignWriting }
+ { "1E00 }{ Glagolitic~ Supplement }
+ { "1E80 }{ Mende~ Kikakui }
+ { "1E90 }{ Adlam }
+ { "1EE0 }{ Arabic~ Mathematical~ Alphabetic~ Symbols }
+ { "1F00 }{ Mahjong~ Tiles }
+ { "1F03 }{ Domino~ Tiles }
+ { "1F0A }{ Playing~ Cards }
+ { "1F10 }{ Enclosed~ Alphanumeric~ Supplement }
+ { "1F20 }{ Enclosed~ Ideographic~ Supplement }
+ { "1F30 }{ Miscellaneous~ Symbols~ and~ Pictographs }
+ { "1F60 }{ Emoticons }
+ { "1F65 }{ Ornamental~ Dingbats }
+ { "1F68 }{ Transport~ and~ Map~ Symbols }
+ { "1F70 }{ Alchemical~ Symbols }
+ { "1F78 }{ Geometric~ Shapes~ Extended }
+ { "1F80 }{ Supplemental~ Arrows-C }
+ { "1F90 }{ Supplemental~ Symbols~ and~ Pictographs }
+ { "2000 }{ CJK~ Unified~ Ideographs~ Extension~ B }
+ { "2A70 }{ CJK~ Unified~ Ideographs~ Extension~ C }
+ { "2B74 }{ CJK~ Unified~ Ideographs~ Extension~ D }
+ { "2B82 }{ CJK~ Unified~ Ideographs~ Extension~ E }
+ { "2CEB }{ CJK~ Unified~ Ideographs~ Extension~ F }
+ { "2F80 }{ CJK~ Compatibility~ Ideographs~ Supplement }
+ { "E010 }{ Tags }
+ { "E000 }{ Variation~ Selectors~ Supplement }
+ { "F000 }{ Supplementary~ Private~ Use~ Area-A }
+ }
+ { \tl_use:N \g__fmuft_block_title_tl }
+ }
+}
+\bool_new:N \l__fmuft_display_block_bool
+\tl_new:N \l__fmuft_display_block_action_tl
+\keys_define:nn {__fmuft}
+ {
+ ,display-block .choice:
+ ,display-block / titles .code:n =
+ \bool_set_true:N \l__fmuft_display_block_bool
+ \tl_set:Nn \l__fmuft_display_block_action_tl {\\}
+ ,display-block / rules .code:n =
+ \bool_set_false:N \l__fmuft_display_block_bool
+ \tl_set:Nn \l__fmuft_display_block_action_tl {\\ \midrule}
+ ,display-block / none .code:n =
+ \bool_set_false:N \l__fmuft_display_block_bool
+ \tl_set:Nn \l__fmuft_display_block_action_tl {\\}
+ ,display-block .initial:n = titles
+ }
+\ExplSyntaxOff
+\RequirePackage{longtable,booktabs,caption,fontspec}
+\ProcessKeysPackageOptions{__fmuft}
+
+\endinput
+%%
+%% End of file `unicodefonttable.sty'.
diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check
index f1863c5df4b..3a93de35c47 100755
--- a/Master/tlpkg/bin/tlpkg-ctan-check
+++ b/Master/tlpkg/bin/tlpkg-ctan-check
@@ -820,7 +820,7 @@ my @TLP_working = qw(
unfonts-core unfonts-extra
uni-titlepage uni-wtal-ger uni-wtal-lin
unicode-alphabets unicode-data unicode-bidi unicode-math
- unifith uninormalize uniquecounter unisugar
+ unicodefonttable unifith uninormalize uniquecounter unisugar
unitconv unitipa unitn-bimrep units unitsdef
universa universalis univie-ling unizgklasa
unravel unswcover
diff --git a/Master/tlpkg/libexec/ctan2tds b/Master/tlpkg/libexec/ctan2tds
index ae8c3e39801..a3fab12d123 100755
--- a/Master/tlpkg/libexec/ctan2tds
+++ b/Master/tlpkg/libexec/ctan2tds
@@ -2312,6 +2312,7 @@ $standardtex
'underscore', '^..[^s].*\.sty', # not miscdoc.sty
'undolabl', '\.sty|[^c]\.cfg', # omit ltxdoc.cfg, would be system-wide
'unicode-alphabets', '\..sv|' . $standardtex,
+ 'unicodefonttable', '(\.sty|unicodefont.tex)$', # not .cls
'uninormalize', '\.lua|' . $standardtex,
'unitn-bimrep','\.jpg|' . $standardtex,
'univie-ling', 'univie.*logo.*.pdf|' . $standardtex,
diff --git a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
index b72bbe641e2..d129ad07609 100644
--- a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
@@ -1306,6 +1306,7 @@ depend underlin
depend underoverlap
depend undolabl
depend uni-titlepage
+depend unicodefonttable
depend unitconv
depend unitipa
depend units
diff --git a/Master/tlpkg/tlpsrc/unicodefonttable.tlpsrc b/Master/tlpkg/tlpsrc/unicodefonttable.tlpsrc
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/unicodefonttable.tlpsrc