summaryrefslogtreecommitdiff
path: root/macros/latex/contrib
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-03-20 03:00:57 +0000
committerNorbert Preining <norbert@preining.info>2022-03-20 03:00:57 +0000
commit932716f98734dec3d6502355f5618e5895729499 (patch)
tree327459c3a9a27ca994d0d2b6f6416ae9d93c9c54 /macros/latex/contrib
parent964a2d4f61e066388beb5d776bf9c163a3f4fd98 (diff)
CTAN sync 202203200300
Diffstat (limited to 'macros/latex/contrib')
-rw-r--r--macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/README.md6
-rw-r--r--macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/demo/trigon_demo.pdfbin416666 -> 416694 bytes
-rw-r--r--macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/docs/trigontheme.pdfbin366853 -> 367005 bytes
-rw-r--r--macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamercolorthemetrigon.dtx2
-rw-r--r--macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerfontthemetrigon.dtx2
-rw-r--r--macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerinnerthemetrigon.dtx8
-rw-r--r--macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerouterthemetrigon.dtx10
-rw-r--r--macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerthemetrigon.dtx2
-rw-r--r--macros/latex/contrib/functional/README.txt2
-rw-r--r--macros/latex/contrib/functional/functional.pdfbin189483 -> 481941 bytes
-rw-r--r--macros/latex/contrib/functional/functional.sty1300
-rw-r--r--macros/latex/contrib/functional/functional.tex3729
-rw-r--r--macros/latex/contrib/thuthesis/CHANGELOG.md272
-rw-r--r--macros/latex/contrib/thuthesis/README.md8
-rw-r--r--macros/latex/contrib/thuthesis/data/appendix-translation.tex7
-rw-r--r--macros/latex/contrib/thuthesis/data/chap04.tex2
-rw-r--r--macros/latex/contrib/thuthesis/ref/appendix.bib2
-rw-r--r--macros/latex/contrib/thuthesis/ref/refs.bib4
-rw-r--r--macros/latex/contrib/thuthesis/spine.pdfbin22266 -> 18789 bytes
-rw-r--r--macros/latex/contrib/thuthesis/thusetup.tex8
-rw-r--r--macros/latex/contrib/thuthesis/thuthesis-author-year.bbx31
-rw-r--r--macros/latex/contrib/thuthesis/thuthesis-author-year.bst201
-rw-r--r--macros/latex/contrib/thuthesis/thuthesis-bachelor.bst195
-rw-r--r--macros/latex/contrib/thuthesis/thuthesis-example.pdfbin405257 -> 378207 bytes
-rw-r--r--macros/latex/contrib/thuthesis/thuthesis-example.tex11
-rw-r--r--macros/latex/contrib/thuthesis/thuthesis-numeric.bbx30
-rw-r--r--macros/latex/contrib/thuthesis/thuthesis-numeric.bst193
-rw-r--r--macros/latex/contrib/thuthesis/thuthesis.dtx253
-rw-r--r--macros/latex/contrib/thuthesis/thuthesis.pdfbin1147400 -> 1008818 bytes
29 files changed, 5594 insertions, 684 deletions
diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/README.md b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/README.md
index f53446ab8c..2643816c1f 100644
--- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/README.md
+++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/README.md
@@ -59,7 +59,7 @@ To install a stable version of this theme, please refer to update instructions
of your TeX distribution. Trigon has been on
[CTAN](https://ctan.org/pkg/beamertheme-trigon) since March 2021. For users of
typical TeX distributions (TexLive, MacTeX, MikTeX), simply updating your
-package list should install trigon on your system.
+package list should install Trigon on your system.
If you want to use the cutting-edge development version of Trigon, you can
install it manually by following these steps:
@@ -77,7 +77,7 @@ install it manually by following these steps:
### Overleaf
-Since October 2021, [TexLive 2011 is availabe on
+Since October 2021, [TexLive 2021 is available on
Overleaf](https://www.overleaf.com/blog/tex-live-2021-now-available). Trigon is
therefore automatically supported for new documents. If you want to switch older
documents to use the Trigon theme, you need to [select TexLive 2021 or higher as
@@ -85,7 +85,7 @@ your TeX Live
version](https://www.overleaf.com/blog/new-feature-select-your-tex-live-compiler-version)
(this may cause issues with other packages used in your presentation).
-In addition to that, a template project was created and is publicly availabe in
+In addition to that, a template project was created and is publicly available in
the [Overleaf Gallery][overleaf-gallery] to bootstrap your presentation.
## Usage
diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/demo/trigon_demo.pdf b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/demo/trigon_demo.pdf
index 157574bf15..0b5b1c54dd 100644
--- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/demo/trigon_demo.pdf
+++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/demo/trigon_demo.pdf
Binary files differ
diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/docs/trigontheme.pdf b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/docs/trigontheme.pdf
index f70379b53a..44f97f0726 100644
--- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/docs/trigontheme.pdf
+++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/docs/trigontheme.pdf
Binary files differ
diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamercolorthemetrigon.dtx b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamercolorthemetrigon.dtx
index 9e5780a7e7..e45237be4d 100644
--- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamercolorthemetrigon.dtx
+++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamercolorthemetrigon.dtx
@@ -13,7 +13,7 @@
% \iffalse
%<*package>
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{beamercolorthemetrigon}[2022/03/10 v0.6.3 Trigon color theme]
+\ProvidesPackage{beamercolorthemetrigon}[2022/03/19 v0.6.4 Trigon color theme]
%</package>
% \fi
% \CheckSum{0}
diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerfontthemetrigon.dtx b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerfontthemetrigon.dtx
index 0d2d1b15ba..d3c8c302d5 100644
--- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerfontthemetrigon.dtx
+++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerfontthemetrigon.dtx
@@ -13,7 +13,7 @@
% \iffalse
%<*package>
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{beamerfontthemetrigon}[2022/03/10 v0.6.3 Trigon font theme]
+\ProvidesPackage{beamerfontthemetrigon}[2022/03/19 v0.6.4 Trigon font theme]
%</package>
% \fi
% \CheckSum{0}
diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerinnerthemetrigon.dtx b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerinnerthemetrigon.dtx
index 5726c1a543..a0adf0a1c4 100644
--- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerinnerthemetrigon.dtx
+++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerinnerthemetrigon.dtx
@@ -13,7 +13,7 @@
% \iffalse
%<*package>
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{beamerinnerthemetrigon}[2022/03/10 v0.6.3 Trigon inner theme]
+\ProvidesPackage{beamerinnerthemetrigon}[2022/03/19 v0.6.4 Trigon inner theme]
%</package>
% \fi
% \CheckSum{0}
@@ -51,9 +51,9 @@
% |\includegraphics|, so it accepts the same options.
% \begin{macrocode}
\def\logbig{}
-\newcommand\biglogo[2][width=0.28\textwidth]{
- \ifx#2\@empty\else
- \def\logbig{\includegraphics[#1]{#2}}
+\newcommand*\biglogo[2][width=0.28\textwidth]{
+ \ifx{#2}\@empty\else
+ \edef\logbig{\includegraphics[#1]{#2}}
\fi
}
% \end{macrocode}
diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerouterthemetrigon.dtx b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerouterthemetrigon.dtx
index de5dc23c16..29eaa37c40 100644
--- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerouterthemetrigon.dtx
+++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerouterthemetrigon.dtx
@@ -13,7 +13,7 @@
% \iffalse
%<*package>
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{beamerouterthemetrigon}[2022/03/10 v0.6.3 Trigon outer theme]
+\ProvidesPackage{beamerouterthemetrigon}[2022/03/19 v0.6.4 Trigon outer theme]
%</package>
% \fi
% \CheckSum{0}
@@ -41,10 +41,10 @@
% |\includegraphics|, so it accepts the same options.
% \begin{macrocode}
\def\logsmall{}
-\newcommand\smalllogo[2][width=20pt]{
- \ifx#2\@empty\else
- \def\logsmall{\includegraphics[#1]{#2}}
- \fi
+\newcommand*\smalllogo[2][width=20pt]{
+\ifx{#2}\@empty\else
+ \edef\logsmall{\includegraphics[#1]{#2}}
+\fi
}
% \end{macrocode}
%
diff --git a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerthemetrigon.dtx b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerthemetrigon.dtx
index f2c56ad5ea..71fd1a5978 100644
--- a/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerthemetrigon.dtx
+++ b/macros/latex/contrib/beamer-contrib/themes/beamertheme-trigon/source/beamerthemetrigon.dtx
@@ -13,7 +13,7 @@
% \iffalse
%<*package>
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{beamerthemetrigon}[2022/03/10 v0.6.3 Trigon Beamer theme]
+\ProvidesPackage{beamerthemetrigon}[2022/03/19 v0.6.4 Trigon Beamer theme]
%</package>
% \fi
% \CheckSum{0}
diff --git a/macros/latex/contrib/functional/README.txt b/macros/latex/contrib/functional/README.txt
index fcb1672c0c..58c2081c9a 100644
--- a/macros/latex/contrib/functional/README.txt
+++ b/macros/latex/contrib/functional/README.txt
@@ -1,4 +1,4 @@
-Functional: LaTeX2 functional interfaces to LaTeX3 programming layer
+Functional: LaTeX2 functional interfaces for LaTeX3 programming layer
Copyright : 2022 (c) Jianrui Lyu <tolvjr@163.com>
Repository: https://github.com/lvjr/functional
Repository: https://bitbucket.org/lvjr/functional
diff --git a/macros/latex/contrib/functional/functional.pdf b/macros/latex/contrib/functional/functional.pdf
index f9f553a0da..e4f7ca1b8f 100644
--- a/macros/latex/contrib/functional/functional.pdf
+++ b/macros/latex/contrib/functional/functional.pdf
Binary files differ
diff --git a/macros/latex/contrib/functional/functional.sty b/macros/latex/contrib/functional/functional.sty
index 95e5ada3dc..dcc863b3c5 100644
--- a/macros/latex/contrib/functional/functional.sty
+++ b/macros/latex/contrib/functional/functional.sty
@@ -1,22 +1,24 @@
%%% -*- coding: utf-8 -*-
%% ----------------------------------------------------------------------------
-%% Functional: LaTeX2 functional interfaces to LaTeX3 programming layer
+%% Functional: LaTeX2 functional interfaces for LaTeX3 programming layer
%% Copyright : 2022 (c) Jianrui Lyu <tolvjr@163.com>
%% Repository: https://github.com/lvjr/functional
+%% Repository: https://bitbucket.org/lvjr/functional
%% License : The LaTeX Project Public License 1.3c
%% ----------------------------------------------------------------------------
%%% --------------------------------------------------------
-%%> \section{Interfaces for Function Definitions (l3basics)}
+%%> \section{Interfaces for Functional Programming (Prg)}
%%% --------------------------------------------------------
\NeedsTeXFormat{LaTeX2e}[2018-04-01]
\RequirePackage{expl3}
-\ProvidesExplPackage{functional}{2022-03-10}{2022A}
- {^^JLaTeX2 functional interfaces to LaTeX3 programming layer}
+\ProvidesExplPackage{functional}{2022-03-19}{2022B}
+ {^^JLaTeX2 functional interfaces for LaTeX3 programming layer}
\cs_generate_variant:Nn \iow_log:n { V }
+\cs_generate_variant:Nn \tl_log:n { e }
\cs_generate_variant:Nn \tl_set:Nn { Ne }
\tl_new:N \gResultTl
@@ -51,16 +53,6 @@
\tl_const:Nn \c__fun_parameter_called_vii_tl { {#7} }
\tl_const:Nn \c__fun_parameter_called_viii_tl { {#8} }
\tl_const:Nn \c__fun_parameter_called_ix_tl { {#9} }
-\tl_new:N \l__fun_argument_tl
-\tl_new:N \l__fun_argument_i_tl
-\tl_new:N \l__fun_argument_ii_tl
-\tl_new:N \l__fun_argument_iii_tl
-\tl_new:N \l__fun_argument_iv_tl
-\tl_new:N \l__fun_argument_v_tl
-\tl_new:N \l__fun_argument_vi_tl
-\tl_new:N \l__fun_argument_vii_tl
-\tl_new:N \l__fun_argument_viii_tl
-\tl_new:N \l__fun_argument_ix_tl
%% #1: function name; #2: argument specification; #3 function body
\cs_new_protected:Npn \__fun_new_function:Nnn #1 #2 #3
@@ -113,13 +105,18 @@
\cs_set_eq:NN \PrgNewConditional \__fun_new_conditional:Nnn
+\int_new:N \g__fun_nesting_level_int
+
%% #1: function name; #2: argument specifications; #3 parameters tl defined
%% Some times we need to create a function without arguments
\cs_new_protected:Npn \__fun_new_with_arg_:Nnn #1 #2 #3
{
\cs_new_protected:Npn #1 #3
{
+ \int_gincr:N \g__fun_nesting_level_int
\__fun_evaluate:Nn #1 {#2}
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
}
}
\cs_generate_variant:Nn \__fun_new_with_arg_:Nnn { NnV }
@@ -129,8 +126,11 @@
{
\cs_new_protected:Npn #1 #3
{
- \tl_set:Nn \l__fun_argument_i_tl { ##1 }
+ \int_gincr:N \g__fun_nesting_level_int
+ \__fun_one_argument_gset:nn { 1 } { ##1 }
\__fun_evaluate:Nn #1 {#2}
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
}
}
\cs_generate_variant:Nn \__fun_new_with_arg_i:Nnn { NnV }
@@ -140,9 +140,12 @@
{
\cs_new_protected:Npn #1 #3
{
- \tl_set:Nn \l__fun_argument_i_tl { ##1 }
- \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
+ \int_gincr:N \g__fun_nesting_level_int
+ \__fun_one_argument_gset:nn { 1 } { ##1 }
+ \__fun_one_argument_gset:nn { 2 } { ##2 }
\__fun_evaluate:Nn #1 {#2}
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
}
}
\cs_generate_variant:Nn \__fun_new_with_arg_ii:Nnn { NnV }
@@ -152,10 +155,13 @@
{
\cs_new_protected:Npn #1 #3
{
- \tl_set:Nn \l__fun_argument_i_tl { ##1 }
- \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
- \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
+ \int_gincr:N \g__fun_nesting_level_int
+ \__fun_one_argument_gset:nn { 1 } { ##1 }
+ \__fun_one_argument_gset:nn { 2 } { ##2 }
+ \__fun_one_argument_gset:nn { 3 } { ##3 }
\__fun_evaluate:Nn #1 {#2}
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
}
}
\cs_generate_variant:Nn \__fun_new_with_arg_iii:Nnn { NnV }
@@ -165,11 +171,14 @@
{
\cs_new_protected:Npn #1 #3
{
- \tl_set:Nn \l__fun_argument_i_tl { ##1 }
- \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
- \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
- \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
+ \int_gincr:N \g__fun_nesting_level_int
+ \__fun_one_argument_gset:nn { 1 } { ##1 }
+ \__fun_one_argument_gset:nn { 2 } { ##2 }
+ \__fun_one_argument_gset:nn { 3 } { ##3 }
+ \__fun_one_argument_gset:nn { 4 } { ##4 }
\__fun_evaluate:Nn #1 {#2}
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
}
}
\cs_generate_variant:Nn \__fun_new_with_arg_iv:Nnn { NnV }
@@ -179,12 +188,15 @@
{
\cs_new_protected:Npn #1 #3
{
- \tl_set:Nn \l__fun_argument_i_tl { ##1 }
- \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
- \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
- \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
- \tl_set:Nn \l__fun_argument_v_tl { ##5 }
+ \int_gincr:N \g__fun_nesting_level_int
+ \__fun_one_argument_gset:nn { 1 } { ##1 }
+ \__fun_one_argument_gset:nn { 2 } { ##2 }
+ \__fun_one_argument_gset:nn { 3 } { ##3 }
+ \__fun_one_argument_gset:nn { 4 } { ##4 }
+ \__fun_one_argument_gset:nn { 5 } { ##5 }
\__fun_evaluate:Nn #1 {#2}
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
}
}
\cs_generate_variant:Nn \__fun_new_with_arg_v:Nnn { NnV }
@@ -194,13 +206,16 @@
{
\cs_new_protected:Npn #1 #3
{
- \tl_set:Nn \l__fun_argument_i_tl { ##1 }
- \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
- \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
- \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
- \tl_set:Nn \l__fun_argument_v_tl { ##5 }
- \tl_set:Nn \l__fun_argument_vi_tl { ##6 }
+ \int_gincr:N \g__fun_nesting_level_int
+ \__fun_one_argument_gset:nn { 1 } { ##1 }
+ \__fun_one_argument_gset:nn { 2 } { ##2 }
+ \__fun_one_argument_gset:nn { 3 } { ##3 }
+ \__fun_one_argument_gset:nn { 4 } { ##4 }
+ \__fun_one_argument_gset:nn { 5 } { ##5 }
+ \__fun_one_argument_gset:nn { 6 } { ##6 }
\__fun_evaluate:Nn #1 {#2}
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
}
}
\cs_generate_variant:Nn \__fun_new_with_arg_vi:Nnn { NnV }
@@ -210,14 +225,17 @@
{
\cs_new_protected:Npn #1 #3
{
- \tl_set:Nn \l__fun_argument_i_tl { ##1 }
- \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
- \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
- \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
- \tl_set:Nn \l__fun_argument_v_tl { ##5 }
- \tl_set:Nn \l__fun_argument_vi_tl { ##6 }
- \tl_set:Nn \l__fun_argument_vii_tl { ##7 }
+ \int_gincr:N \g__fun_nesting_level_int
+ \__fun_one_argument_gset:nn { 1 } { ##1 }
+ \__fun_one_argument_gset:nn { 2 } { ##2 }
+ \__fun_one_argument_gset:nn { 3 } { ##3 }
+ \__fun_one_argument_gset:nn { 4 } { ##4 }
+ \__fun_one_argument_gset:nn { 5 } { ##5 }
+ \__fun_one_argument_gset:nn { 6 } { ##6 }
+ \__fun_one_argument_gset:nn { 7 } { ##7 }
\__fun_evaluate:Nn #1 {#2}
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
}
}
\cs_generate_variant:Nn \__fun_new_with_arg_vii:Nnn { NnV }
@@ -227,15 +245,18 @@
{
\cs_new_protected:Npn #1 #3
{
- \tl_set:Nn \l__fun_argument_i_tl { ##1 }
- \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
- \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
- \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
- \tl_set:Nn \l__fun_argument_v_tl { ##5 }
- \tl_set:Nn \l__fun_argument_vi_tl { ##6 }
- \tl_set:Nn \l__fun_argument_vii_tl { ##7 }
- \tl_set:Nn \l__fun_argument_viii_tl { ##8 }
+ \int_gincr:N \g__fun_nesting_level_int
+ \__fun_one_argument_gset:nn { 1 } { ##1 }
+ \__fun_one_argument_gset:nn { 2 } { ##2 }
+ \__fun_one_argument_gset:nn { 3 } { ##3 }
+ \__fun_one_argument_gset:nn { 4 } { ##4 }
+ \__fun_one_argument_gset:nn { 5 } { ##5 }
+ \__fun_one_argument_gset:nn { 6 } { ##6 }
+ \__fun_one_argument_gset:nn { 7 } { ##7 }
+ \__fun_one_argument_gset:nn { 8 } { ##8 }
\__fun_evaluate:Nn #1 {#2}
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
}
}
\cs_generate_variant:Nn \__fun_new_with_arg_viii:Nnn { NnV }
@@ -245,39 +266,39 @@
{
\cs_new_protected:Npn #1 #3
{
- \tl_set:Nn \l__fun_argument_i_tl { ##1 }
- \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
- \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
- \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
- \tl_set:Nn \l__fun_argument_v_tl { ##5 }
- \tl_set:Nn \l__fun_argument_vi_tl { ##6 }
- \tl_set:Nn \l__fun_argument_vii_tl { ##7 }
- \tl_set:Nn \l__fun_argument_viii_tl { ##8 }
- \tl_set:Nn \l__fun_argument_ix_tl { ##9 }
+ \int_gincr:N \g__fun_nesting_level_int
+ \__fun_one_argument_gset:nn { 1 } { ##1 }
+ \__fun_one_argument_gset:nn { 2 } { ##2 }
+ \__fun_one_argument_gset:nn { 3 } { ##3 }
+ \__fun_one_argument_gset:nn { 4 } { ##4 }
+ \__fun_one_argument_gset:nn { 5 } { ##5 }
+ \__fun_one_argument_gset:nn { 6 } { ##6 }
+ \__fun_one_argument_gset:nn { 7 } { ##7 }
+ \__fun_one_argument_gset:nn { 8 } { ##8 }
+ \__fun_one_argument_gset:nn { 9 } { ##9 }
\__fun_evaluate:Nn #1 {#2}
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
}
}
\cs_generate_variant:Nn \__fun_new_with_arg_ix:Nnn { NnV }
-\int_new:N \g__fun_nesting_level_int
-\int_new:N \l__fun_argtype_number_int
\tl_new:N \l__fun_argtype_tl
\tl_const:Nn \c__fun_argtype_m_tl { m }
\tl_const:Nn \c__fun_argtype_M_tl { M }
\tl_const:Nn \c__fun_argtype_n_tl { n }
\tl_const:Nn \c__fun_argtype_N_tl { N }
+\tl_new:N \l__fun_argument_tl
%% #1: function name; #2: argument specifications
\cs_new_protected:Npn \__fun_evaluate:Nn #1 #2
{
- \int_zero:N \l__fun_argtype_number_int
- \int_gincr:N \g__fun_nesting_level_int
+ \__fun_argtype_index_gzero:
\__fun_arguments_gclear:
\tl_map_variable:nNn { #2 } \l__fun_argtype_tl % spaces are ignored
{
- \int_incr:N \l__fun_argtype_number_int
- \tl_set_eq:Nc \l__fun_argument_tl
- { l__fun_argument_ \int_to_roman:n { \l__fun_argtype_number_int } _tl }
+ \__fun_argtype_index_gincr:
+ \__fun_one_argument_get:eN { \__fun_argtype_index_use: } \l__fun_argument_tl
\tl_case:Nn \l__fun_argtype_tl
{
\c__fun_argtype_m_tl
@@ -300,19 +321,14 @@
}
\__fun_arguments_log:N #1
\__fun_arguments_called:c { __fun_defined_ \cs_to_str:N #1 : w }
- \int_gdecr:N \g__fun_nesting_level_int
- \__fun_return_result:
}
-\cs_set_eq:NN \__fun_cs_temp:w \scan_stop:
-
\cs_new_protected:Npn \__fun_evaluate_and_put_argument:N #1
{
- \cs_set_eq:Nc \__fun_cs_temp:w
+ \cs_if_exist:cTF
{
__fun_defined_ \exp_last_unbraced:Ne \cs_to_str:N { \tl_head:N #1 } : w
}
- \cs_if_exist:NTF \__fun_cs_temp:w
{
#1
\__fun_arguments_gput:e { { \exp_not:V \gResultTl } }
@@ -322,6 +338,57 @@
}
}
+%% #1: argument number; #2: token lists
+\cs_new_protected:Npn \__fun_one_argument_gset:nn #1 #2
+ {
+ \tl_gset:cn
+ { g__fun_one_argument_ \int_use:N \g__fun_nesting_level_int _#1_tl } { #2 }
+ %\__fun_one_argument_log:nn { #1 } { set }
+ }
+
+%% #1: argument number; #2: variable of token lists
+\cs_new_protected:Npn \__fun_one_argument_get:nN #1 #2
+ {
+ \tl_set_eq:Nc
+ #2 { g__fun_one_argument_ \int_use:N \g__fun_nesting_level_int _ #1 _tl }
+ %\__fun_one_argument_log:nn { #1 } { get }
+ }
+\cs_generate_variant:Nn \__fun_one_argument_get:nN { eN }
+
+%% #1: argument number; #2: get or set
+\cs_new_protected:Npn \__fun_one_argument_log:nn #1 #2
+ {
+ \tl_log:e
+ {
+ #2 ~ level _ \int_use:N \g__fun_nesting_level_int _ arg _ #1 ~ = ~
+ \exp_not:v
+ { g__fun_one_argument_ \int_use:N \g__fun_nesting_level_int _#1_tl }
+ }
+ }
+
+\int_new:c { g__fun_argtype_index_ 1 _int }
+\int_new:c { g__fun_argtype_index_ 2 _int }
+\int_new:c { g__fun_argtype_index_ 3 _int }
+\int_new:c { g__fun_argtype_index_ 4 _int }
+\int_new:c { g__fun_argtype_index_ 5 _int }
+
+\cs_new_protected:Npn \__fun_argtype_index_gzero:
+ {
+ \int_gzero_new:c
+ { g__fun_argtype_index_ \int_use:N \g__fun_nesting_level_int _int }
+ }
+
+\cs_new_protected:Npn \__fun_argtype_index_gincr:
+ {
+ \int_gincr:c
+ { g__fun_argtype_index_ \int_use:N \g__fun_nesting_level_int _int }
+ }
+
+\cs_new:Npn \__fun_argtype_index_use:
+ {
+ \int_use:c { g__fun_argtype_index_ \int_use:N \g__fun_nesting_level_int _int }
+ }
+
\cs_new_protected:Npn \__fun_arguments_called:N #1
{
\exp_last_unbraced:Nv
@@ -350,6 +417,12 @@
}
\cs_generate_variant:Nn \__fun_arguments_gput:n { e }
+\cs_set_eq:NN \Break \prg_break:
+\cs_set_eq:NN \PrgBreak \prg_break:
+
+\cs_set_eq:NN \BreakDo \prg_break:n
+\cs_set_eq:NN \PrgBreakDo \prg_break:n
+
\cs_new_protected:Npn \__fun_put_result:n #1
{
\tl_gput_right:Nn \gResultTl { #1 }
@@ -361,27 +434,6 @@
\__fun_put_result:n { #1 }
}
-\PrgNewFunction \Name { m }
- {
- \exp_args:Nc \__fun_put_result:n { #1 }
- }
-\cs_set_eq:NN \UseName \Name
-
-\PrgNewFunction \Expand { m }
- {
- \__fun_put_result:e { #1 }
- }
-\cs_set_eq:NN \UseExpand \Expand
-
-\PrgNewFunction \Value { M }
- {
- \__fun_put_result:V #1
- }
-\cs_set_eq:NN \UseValue \Value
-
-\cs_set_eq:NN \ExpNot \exp_not:n
-\cs_set_eq:NN \ExpValue \exp_not:V
-
\cs_new_protected:Npn \__fun_return_result:
{
\int_compare:nNnT { \g__fun_nesting_level_int } = { 0 }
@@ -484,28 +536,50 @@
\Functional { scoping = false, tracing = false }
-\PrgNewFunction \UseOne { n }
+\cs_new_protected:Npn \__fun_ignore_spaces_on:
{
- \Result { #1 }
+ \ExplSyntaxOn
+ \char_set_catcode_math_subscript:N \_
+ \char_set_catcode_other:N \:
}
+\cs_set_eq:NN \IgnoreSpacesOn \__fun_ignore_spaces_on:
+\cs_set_eq:NN \IgnoreSpacesOff \ExplSyntaxOff
-\PrgNewFunction \GobbleOne { n }
+%%% --------------------------------------------------------
+%%> \section{Interfaces for Argument Using (Use)}
+%%% --------------------------------------------------------
+
+\PrgNewFunction \Name { m }
{
- \Result { }
+ \exp_args:Nc \__fun_put_result:n { #1 }
}
+\cs_set_eq:NN \UseName \Name
-\PrgNewFunction \UseGobble { n n }
+\PrgNewFunction \Value { M }
{
- \UseOne { #1 }
+ \__fun_put_result:V #1
}
+\cs_set_eq:NN \UseValue \Value
-\PrgNewFunction \GobbleUse { n n }
+\PrgNewFunction \Expand { m }
{
- \UseOne { #2 }
+ \__fun_put_result:e { #1 }
}
+\cs_set_eq:NN \UseExpand \Expand
+
+\cs_set_eq:NN \ExpNot \exp_not:n
+\cs_set_eq:NN \ExpValue \exp_not:V
+
+\PrgNewFunction \UseOne { n } { \Result { #1 } }
+
+\PrgNewFunction \GobbleOne { n } { \Result { } }
+
+\PrgNewFunction \UseGobble { n n } { \UseOne { #1 } }
+
+\PrgNewFunction \GobbleUse { n n } { \UseOne { #2 } }
%%% --------------------------------------------------------
-%%> \section{Interfaces for Control Structures (l3prg)}
+%%> \section{Interfaces for Control Structures (Bool)}
%%% --------------------------------------------------------
\bool_const:Nn \cTrueBool { \c_true_bool }
@@ -519,8 +593,14 @@
\bool_new:N \gTmpiBool \bool_new:N \gTmpjBool \bool_new:N \gTmpkBool
\bool_new:N \g@Funx@Bool \bool_new:N \g@Funy@Bool \bool_new:N \g@Funz@Bool
-\cs_set_eq:NN \BoolNew \bool_new:N
-\cs_set_eq:NN \BoolLog \bool_log:N
+\PrgNewFunction \BoolNew { M } { \bool_new:N #1 }
+
+\PrgNewFunction \BoolConst { M m } { \bool_const:Nn #1 { #2 } }
+
+\PrgNewFunction \BoolSet { M m } {
+ \__fun_do_assignment:Nnn #1
+ { \bool_gset:Nn #1 { #2 } } { \bool_set:Nn #1 { #2 } }
+}
\PrgNewFunction \BoolSetTrue { M }
{
@@ -532,15 +612,59 @@
\__fun_do_assignment:Nnn #1 { \bool_gset_false:N #1 } { \bool_set_false:N #1 }
}
-\PrgNewConditional \BoolIf { N }
+\PrgNewFunction \BoolSetEq { M M }
{
- \Result { #1 }
+ \__fun_do_assignment:Nnn #1
+ { \bool_gset_eq:NN #1 #2 } { \bool_set_eq:NN #1 #2 }
+ }
+
+\PrgNewFunction \BoolLog { m } { \bool_log:n { #1 } }
+
+\PrgNewFunction \BoolVarLog { M } { \bool_log:N #1 }
+
+\PrgNewFunction \BoolShow { m } { \bool_show:n { #1 } }
+
+\PrgNewFunction \BoolVarShow { M } { \bool_show:N #1 }
+
+\PrgNewConditional \BoolIfExist { M }
+ {
+ \bool_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \BoolVarIf { M } { \Result { #1 } }
+
+\PrgNewConditional \BoolVarNot { M }
+ {
+ \bool_if:NTF #1
+ { \Result { \cFalseBool } } { \Result { \cTrueBool } }
+ }
+
+\PrgNewConditional \BoolVarAnd { M M }
+ {
+ \bool_lazy_and:nnTF {#1} {#2}
+ { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \BoolVarOr { M M }
+ {
+ \bool_lazy_or:nnTF {#1} {#2}
+ { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \BoolVarXor { M M }
+ {
+ \bool_xor:nnTF {#1} {#2}
+ { \Result { \cTrueBool } } { \Result { \cFalseBool } }
}
%%% --------------------------------------------------------
-%%> \section{Interfaces for Token Lists (l3tl)}
+%%> \section{Interfaces for Token Lists (Tl)}
%%% --------------------------------------------------------
+\tl_set_eq:NN \cEmptyTl \c_empty_tl
+\tl_set_eq:NN \cSpaceTl \c_space_tl
+\tl_set_eq:NN \cNoValueTl \c_novalue_tl
+
\tl_new:N \lTmpaTl \tl_new:N \lTmpbTl \tl_new:N \lTmpcTl
\tl_new:N \lTmpiTl \tl_new:N \lTmpjTl \tl_new:N \lTmpkTl
\tl_new:N \l@Funx@Tl \tl_new:N \l@Funy@Tl \tl_new:N \l@Funz@Tl
@@ -549,17 +673,48 @@
\tl_new:N \gTmpiTl \tl_new:N \gTmpjTl \tl_new:N \gTmpkTl
\tl_new:N \g@Funx@Tl \tl_new:N \g@Funy@Tl \tl_new:N \g@Funz@Tl
-\cs_set_eq:NN \TlNew \tl_new:N
-\cs_set_eq:NN \TlLog \tl_log:N
+\PrgNewFunction \TlNew { M } { \tl_new:N #1 }
+
+\PrgNewFunction \TlLog { m } { \tl_log:n { #1 } }
+
+\PrgNewFunction \TlVarLog { M } { \tl_log:N #1 }
+
+\PrgNewFunction \TlShow { m } { \tl_show:n { #1 } }
+
+\PrgNewFunction \TlVarShow { M } { \tl_show:N #1 }
+
+\PrgNewFunction \TlUse { M } { \Result { \Value #1 } }
+
+\PrgNewFunction \TlToStr { m } { \Expand { \tl_to_str:n { #1 } } }
+
+\PrgNewFunction \TlVarToStr { M } { \Expand { \tl_to_str:N #1 } }
+
+\PrgNewFunction \TlConst { M m } { \tl_const:Nn #1 { #2 } }
+
+\PrgNewFunction \TlSet { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \tl_gset:Nn #1 {#2} } { \tl_set:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \TlSetEq { M M }
+ {
+ \__fun_do_assignment:Nnn #1 { \tl_gset_eq:NN #1 #2 } { \tl_set_eq:NN #1 #2 }
+ }
+
+\PrgNewFunction \TlConcat { M M M }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \tl_gconcat:NNN #1 #2 #3 } { \tl_concat:NNN #1 #2 #3 }
+ }
\PrgNewFunction \TlClear { M }
{
\__fun_do_assignment:Nnn #1 { \tl_gclear:N #1 } { \tl_clear:N #1 }
}
-\PrgNewFunction \TlSet { M m }
+\PrgNewFunction \TlClearNew { M }
{
- \__fun_do_assignment:Nnn #1 { \tl_gset:Nn #1 {#2} } { \tl_set:Nn #1 {#2} }
+ \__fun_do_assignment:Nnn #1 { \tl_gclear_new:N #1 } { \tl_clear_new:N #1 }
}
\PrgNewFunction \TlPutLeft { M m }
@@ -574,29 +729,339 @@
{ \tl_gput_right:Nn #1 {#2} } { \tl_put_right:Nn #1 {#2} }
}
-\PrgNewFunction \TlUse { M }
+\PrgNewFunction \TlReplaceOnce { M m m }
{
- \Result { \Value #1 }
+ \__fun_do_assignment:Nnn #1
+ { \tl_greplace_once:Nnn #1 {#2} {#3} } { \tl_replace_once:Nnn #1 {#2} {#3} }
}
-\PrgNewConditional \TlIfEmpty { N }
+\PrgNewFunction \TlReplaceAll { M m m }
{
- \tl_if_empty:NTF #1
- { \Result { \cTrueBool } }
- { \Result { \cFalseBool } }
+ \__fun_do_assignment:Nnn #1
+ { \tl_greplace_all:Nnn #1 {#2} {#3} } { \tl_replace_all:Nnn #1 {#2} {#3} }
+ }
+
+\PrgNewFunction \TlRemoveOnce { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \tl_gremove_once:Nn #1 {#2} } { \tl_remove_once:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \TlRemoveAll { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \tl_gremove_all:Nn #1 {#2} } { \tl_remove_all:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \TlTrimSpaces { m } { \Expand { \tl_trim_spaces:n { #1 } } }
+
+\PrgNewFunction \TlVarTrimSpaces { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \tl_gtrim_spaces:N #1 } { \tl_trim_spaces:N #1 }
+ }
+
+\PrgNewFunction \TlCount { m } { \Expand { \tl_count:n { #1 } } }
+
+\PrgNewFunction \TlVarCount { M } { \Expand { \tl_count:N #1 } }
+
+\PrgNewFunction \TlHead { m } { \Expand { \tl_head:n { #1 } } }
+
+\PrgNewFunction \TlVarHead { M } { \Expand { \tl_head:N #1 } }
+
+\PrgNewFunction \TlTail { m } { \Expand { \tl_tail:n { #1 } } }
+
+\PrgNewFunction \TlVarTail { M } { \Expand { \tl_tail:N #1 } }
+
+\PrgNewFunction \TlItem { m m } { \Expand { \tl_item:nn {#1} {#2} } }
+
+\PrgNewFunction \TlVarItem { M m } { \Expand { \tl_item:Nn #1 {#2} } }
+
+\PrgNewFunction \TlRandItem { m } { \Expand { \tl_rand_item:n {#1} } }
+
+\PrgNewFunction \TlVarRandItem { M } { \Expand { \tl_rand_item:N #1 } }
+
+\PrgNewFunction \TlVarCase { M m } { \tl_case:Nn {#1} {#2} }
+\PrgNewFunction \TlVarCaseT { M m n } { \tl_case:NnT {#1} {#2} {#3} }
+\PrgNewFunction \TlVarCaseF { M m n } { \tl_case:NnF {#1} {#2} {#3} }
+\PrgNewFunction \TlVarCaseTF { M m n n } { \tl_case:NnTF {#1} {#2} {#3} {#4} }
+
+\PrgNewFunction \TlMapInline { m n }
+ {
+ \tl_map_inline:nn {#1} {#2}
+ }
+
+\PrgNewFunction \TlVarMapInline { M n }
+ {
+ \tl_map_inline:Nn #1 {#2}
+ }
+
+\PrgNewFunction \TlMapVariable { m M n }
+ {
+ \tl_map_variable:nNn {#1} #2 {#3}
+ }
+
+\PrgNewFunction \TlVarMapVariable { M M n }
+ {
+ \tl_map_variable:NNn #1 #2 {#3}
+ }
+
+\PrgNewConditional \TlIfExist { M }
+ {
+ \tl_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \TlIfEmpty { m }
+ {
+ \tl_if_empty:nTF {#1} { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \TlVarIfEmpty { M }
+ {
+ \tl_if_empty:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \TlIfBlank { m }
+ {
+ \tl_if_blank:nTF {#1} { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \TlIfEq { m m }
+ {
+ \tl_if_eq:nnTF {#1} {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \TlVarIfEq { M M }
+ {
+ \tl_if_eq:NNTF #1 #2 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \TlIfIn { m m }
+ {
+ \tl_if_in:nnTF {#1} {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \TlVarIfIn { M m }
+ {
+ \tl_if_in:NnTF #1 {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \TlIfSingle { m }
+ {
+ \tl_if_single:nTF {#1} { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \TlVarIfSingle { M }
+ {
+ \tl_if_single:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+%%% --------------------------------------------------------
+%%> \section{Interfaces for Strings (Str)}
+%%% --------------------------------------------------------
+
+\str_set_eq:NN \cAmpersandStr \c_ampersand_str
+\str_set_eq:NN \cAttignStr \c_atsign_str
+\str_set_eq:NN \cBackslashStr \c_backslash_str
+\str_set_eq:NN \cLeftBraceStr \c_left_brace_str
+\str_set_eq:NN \cRightBraceStr \c_right_brace_str
+\str_set_eq:NN \cCircumflexStr \c_circumflex_str
+\str_set_eq:NN \cColonStr \c_colon_str
+\str_set_eq:NN \cDollarStr \c_dollar_str
+\str_set_eq:NN \cHashStr \c_hash_str
+\str_set_eq:NN \cPercentStr \c_percent_str
+\str_set_eq:NN \cTildeStr \c_tilde_str
+\str_set_eq:NN \cUnderscoreStr \c_underscore_str
+\str_set_eq:NN \cZeroStr \c_zero_str
+
+\str_new:N \lTmpaStr \str_new:N \lTmpbStr \str_new:N \lTmpcStr
+\str_new:N \lTmpiStr \str_new:N \lTmpjStr \str_new:N \lTmpkStr
+\str_new:N \l@Funx@Str \str_new:N \l@Funy@Str \str_new:N \l@Funz@Str
+
+\str_new:N \gTmpaStr \str_new:N \gTmpbStr \str_new:N \gTmpcStr
+\str_new:N \gTmpiStr \str_new:N \gTmpjStr \str_new:N \gTmpkStr
+\str_new:N \g@Funx@Str \str_new:N \g@Funy@Str \str_new:N \g@Funz@Str
+
+\PrgNewFunction \StrNew { M } { \str_new:N #1 }
+
+\PrgNewFunction \StrLog { m } { \str_log:n { #1 } }
+
+\PrgNewFunction \StrVarLog { M } { \str_log:N #1 }
+
+\PrgNewFunction \StrShow { m } { \str_show:n { #1 } }
+
+\PrgNewFunction \StrVarShow { M } { \str_show:N #1 }
+
+\PrgNewFunction \StrUse { M } { \Result { \Value #1 } }
+
+\PrgNewFunction \StrConst { M m } { \str_const:Nn #1 {#2} }
+
+\PrgNewFunction \StrSet { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \str_gset:Nn #1 {#2} } { \str_set:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \StrSetEq { M M }
+ {
+ \__fun_do_assignment:Nnn #1 { \str_gset_eq:NN #1 #2 } { \str_set_eq:NN #1 #2 }
+ }
+
+\PrgNewFunction \StrConcat { M M M }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \str_gconcat:NNN #1 #2 #3 } { \str_concat:NNN #1 #2 #3 }
+ }
+
+\PrgNewFunction \StrClear { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \str_gclear:N #1 } { \str_clear:N #1 }
+ }
+
+\PrgNewFunction \StrClearNew { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \str_gclear_new:N #1 } { \str_clear_new:N #1 }
+ }
+
+\PrgNewFunction \StrPutLeft { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \str_gput_left:Nn #1 {#2} } { \str_put_left:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \StrPutRight { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \str_gput_right:Nn #1 {#2} } { \str_put_right:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \StrReplaceOnce { M m m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \str_greplace_once:Nnn #1 {#2} {#3} } { \str_replace_once:Nnn #1 {#2} {#3} }
+ }
+
+\PrgNewFunction \StrReplaceAll { M m m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \str_greplace_all:Nnn #1 {#2} {#3} } { \str_replace_all:Nnn #1 {#2} {#3} }
+ }
+
+\PrgNewFunction \StrRemoveOnce { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \str_gremove_once:Nn #1 {#2} } { \str_remove_once:Nn #1 {#2} }
}
-\PrgNewConditional \TlIfEq { N N }
+\PrgNewFunction \StrRemoveAll { M m }
{
- \tl_if_eq:NNTF #1 #2
+ \__fun_do_assignment:Nnn #1
+ { \str_gremove_all:Nn #1 {#2} } { \str_remove_all:Nn #1 {#2} }
+ }
+
+%% Avoid naming confict with xstring package
+\cs_if_exist:NF \StrCount
+ { \PrgNewFunction \StrCount { m } { \Expand { \str_count:n { #1 } } } }
+
+%% Provide another name for \StrCount function
+\PrgNewFunction \StrSize { m } { \Expand { \str_count:n { #1 } } }
+
+\PrgNewFunction \StrVarCount { M } { \Expand { \str_count:N #1 } }
+
+\PrgNewFunction \StrHead { m } { \Expand { \str_head:n { #1 } } }
+
+\PrgNewFunction \StrVarHead { M } { \Expand { \str_head:N #1 } }
+
+\PrgNewFunction \StrTail { m } { \Expand { \str_tail:n { #1 } } }
+
+\PrgNewFunction \StrVarTail { M } { \Expand { \str_tail:N #1 } }
+
+\PrgNewFunction \StrItem { m m } { \Expand { \str_item:nn {#1} {#2} } }
+
+\PrgNewFunction \StrVarItem { M m } { \Expand { \str_item:Nn #1 {#2} } }
+
+\PrgNewFunction \StrCase { m m } { \str_case:nn {#1} {#2} }
+\PrgNewFunction \StrCaseT { m m n } { \str_case:nnT {#1} {#2} {#3} }
+\PrgNewFunction \StrCaseF { m m n } { \str_case:nnF {#1} {#2} {#3} }
+\PrgNewFunction \StrCaseTF { m m n n } { \str_case:nnTF {#1} {#2} {#3} {#4} }
+
+\PrgNewFunction \StrMapInline { m n }
+ {
+ \str_map_inline:nn {#1} {#2}
+ }
+
+\PrgNewFunction \StrVarMapInline { M n }
+ {
+ \str_map_inline:Nn #1 {#2}
+ }
+
+\PrgNewFunction \StrMapVariable { m M n }
+ {
+ \str_map_variable:nNn {#1} #2 {#3}
+ }
+
+\PrgNewFunction \StrVarMapVariable { M M n }
+ {
+ \str_map_variable:NNn #1 #2 {#3}
+ }
+
+\PrgNewConditional \StrIfExist { M }
+ {
+ \str_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \StrVarIfEmpty { M }
+ {
+ \str_if_empty:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \StrIfEq { m m }
+ {
+ \str_if_eq:nnTF {#1} {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \StrVarIfEq { M M }
+ {
+ \str_if_eq:NNTF #1 #2 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \StrIfIn { m m }
+ {
+ \str_if_in:nnTF {#1} {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \StrVarIfIn { M m }
+ {
+ \str_if_in:NnTF #1 {#2} { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+%% Avoid naming confict with xstring package
+\cs_if_exist:NF \StrCompare
+ {
+ \PrgNewConditional \StrCompare { m N m }
+ {
+ \str_compare:nNnTF {#1} #2 {#3}
+ { \Result { \cTrueBool } }
+ { \Result { \cFalseBool } }
+ }
+ }
+
+%% Provide another name for \StrCompare function
+\PrgNewConditional \StrIfCompare { m N m }
+ {
+ \str_compare:nNnTF {#1} #2 {#3}
{ \Result { \cTrueBool } }
{ \Result { \cFalseBool } }
}
%%% --------------------------------------------------------
-%%> \section{Interfaces for Integers (l3int)}
+%%> \section{Interfaces for Integers (Int)}
%%% --------------------------------------------------------
+\cs_set_eq:NN \cZeroInt \c_zero_int
+\cs_set_eq:NN \cOneInt \c_one_int
+\cs_set_eq:NN \cMaxInt \c_max_int
+\cs_set_eq:NN \cMaxRegisterInt \c_max_register_int
+\cs_set_eq:NN \cMaxCharInt \c_max_char_in
+
\int_new:N \lTmpaInt \int_new:N \lTmpbInt \int_new:N \lTmpcInt
\int_new:N \lTmpiInt \int_new:N \lTmpjInt \int_new:N \lTmpkInt
\int_new:N \l@Funx@Int \int_new:N \l@Funy@Int \int_new:N \l@Funz@Int
@@ -605,14 +1070,85 @@
\int_new:N \gTmpiInt \int_new:N \gTmpjInt \int_new:N \gTmpkInt
\int_new:N \g@Funx@Int \int_new:N \g@Funy@Int \int_new:N \g@Funz@Int
-\cs_set_eq:NN \IntNew \int_new:N
-\cs_set_eq:NN \IntLog \int_log:N
+\PrgNewFunction \IntEval { m }
+ {
+ \Result { \Expand { \int_eval:n { #1 } } }
+ }
+
+\PrgNewFunction \IntMathAdd { m m }
+ {
+ \int_set:Nn \l@Funx@Int { \int_eval:n { (#1) + (#2) } }
+ \Result { \Value \l@Funx@Int }
+ }
+
+\PrgNewFunction \IntMathSub { m m }
+ {
+ \int_set:Nn \l@Funx@Int { \int_eval:n { (#1) - (#2) } }
+ \Result { \Value \l@Funx@Int }
+ }
+
+\PrgNewFunction \IntMathMult { m m }
+ {
+ \int_set:Nn \l@Funx@Int { \int_eval:n { (#1) * (#2) } }
+ \Result { \Value \l@Funx@Int }
+ }
+
+\PrgNewFunction \IntMathDiv { m m }
+ {
+ \Expand { \int_div_round:nn { #1 } { #2 } }
+ }
+
+\PrgNewFunction \IntMathDivTruncate { m m }
+ {
+ \Expand { \int_div_truncate:nn { #1 } { #2 } }
+ }
+
+\PrgNewFunction \IntMathSign { m } { \Expand { \int_sign:n { #1 } } }
+
+\PrgNewFunction \IntMathAbs { m } { \Expand { \int_abs:n { #1 } } }
+
+\PrgNewFunction \IntMathMax { m m } { \Expand { \int_max:nn { #1 } { #2 } } }
+
+\PrgNewFunction \IntMathMin { m m } { \Expand { \int_min:nn { #1 } { #2 } } }
+
+\PrgNewFunction \IntMathMod { m m } { \Expand { \int_mod:nn { #1 } { #2 } } }
+
+\PrgNewFunction \IntMathRand { m m } { \Expand { \int_rand:nn { #1 } { #2 } } }
+
+\PrgNewFunction \IntNew { M } { \int_new:N #1 }
+
+\PrgNewFunction \IntConst { M m } { \int_const:Nn #1 { #2 } }
+
+\PrgNewFunction \IntLog { m } { \int_log:n { #1 } }
+
+\PrgNewFunction \IntVarLog { M } { \int_log:N #1 }
+
+\PrgNewFunction \IntShow { m } { \int_show:n { #1 } }
+
+\PrgNewFunction \IntVarShow { M } { \int_show:N #1 }
+
+\PrgNewFunction \IntUse { M } { \Result { \Value #1 } }
+
+\PrgNewFunction \IntSet { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \int_gset:Nn #1 {#2} } { \int_set:Nn #1 {#2} }
+ }
\PrgNewFunction \IntZero { M }
{
\__fun_do_assignment:Nnn #1 { \int_gzero:N #1 } { \int_zero:N #1 }
}
+\PrgNewFunction \IntZeroNew { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \int_gzero_new:N #1 } { \int_zero_new:N #1 }
+ }
+
+\PrgNewFunction \IntSetEq { M M }
+ {
+ \__fun_do_assignment:Nnn #1 { \int_gset_eq:NN #1 #2 } { \int_set_eq:NN #1 #2 }
+ }
+
\PrgNewFunction \IntIncr { M }
{
\__fun_do_assignment:Nnn #1 { \int_gincr:N #1 } { \int_incr:N #1 }
@@ -623,11 +1159,6 @@
\__fun_do_assignment:Nnn #1 { \int_gdecr:N #1 } { \int_decr:N #1 }
}
-\PrgNewFunction \IntSet { M m }
- {
- \__fun_do_assignment:Nnn #1 { \int_gset:Nn #1 {#2} } { \int_set:Nn #1 {#2} }
- }
-
\PrgNewFunction \IntAdd { M m }
{
\__fun_do_assignment:Nnn #1 { \int_gadd:Nn #1 {#2} } { \int_add:Nn #1 {#2} }
@@ -638,49 +1169,524 @@
\__fun_do_assignment:Nnn #1 { \int_gsub:Nn #1 {#2} } { \int_sub:Nn #1 {#2} }
}
-\PrgNewFunction \IntUse { M }
+\PrgNewFunction \IntStepInline { m m m n }
{
- \Result { \Value #1 }
+ \int_step_inline:nnnn { #1 } { #2 } { #3 } { #4 }
}
-\PrgNewFunction \IntEval { m }
+\PrgNewFunction \IntStepVariable { m m m M n }
{
- \Result { \Expand { \int_eval:n { #1 } } }
+ \int_step_variable:nnnNn { #1 } { #2 } { #3 } #4 { #5 }
}
-\PrgNewFunction \IntMathAdd { m m }
+\PrgNewConditional \IntIfExist { M }
{
- \int_set:Nn \l@Funx@Int { \int_eval:n { #1 + #2 } }
- \Result { \Value \l@Funx@Int }
+ \int_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
}
-\PrgNewFunction \IntMathSub { m m }
+\PrgNewConditional \IntIfOdd { m }
{
- \int_set:Nn \l@Funx@Int { \int_eval:n { #1 - #2 } }
- \Result { \Value \l@Funx@Int }
+ \int_if_odd:nTF { #1 } { \Result { \cTrueBool } } { \Result { \cFalseBool } }
}
-\PrgNewFunction \IntMathMult { m m }
+\PrgNewConditional \IntIfEven { m }
{
- \int_set:Nn \l@Funx@Int { \int_eval:n { #1 * #2 } }
- \Result { \Value \l@Funx@Int }
+ \int_if_even:nTF { #1 } { \Result { \cTrueBool } } { \Result { \cFalseBool } }
}
-\PrgNewFunction \IntMathDiv { m m }
+\PrgNewConditional \IntCompare { m N m }
{
- \int_set:Nn \l@Funx@Int { \int_eval:n { #1 / #2 } }
- \Result { \Value \l@Funx@Int }
+ \int_compare:nNnTF {#1} #2 {#3}
+ { \Result { \cTrueBool } }
+ { \Result { \cFalseBool } }
}
-\PrgNewFunction \IntStepVariable { m m m M n }
+\PrgNewFunction \IntCase { m m } { \int_case:nn {#1} {#2} }
+\PrgNewFunction \IntCaseT { m m n } { \int_case:nnT {#1} {#2} {#3} }
+\PrgNewFunction \IntCaseF { m m n } { \int_case:nnF {#1} {#2} {#3} }
+\PrgNewFunction \IntCaseTF { m m n n } { \int_case:nnTF {#1} {#2} {#3} {#4} }
+
+%%% --------------------------------------------------------
+%%> \section{Interfaces for Floating Point Numbers (Fp)}
+%%% --------------------------------------------------------
+
+\fp_set_eq:NN \cZeroFp \c_zero_fp
+\fp_set_eq:NN \cMinusZeroFp \c_minus_zero_fp
+\fp_set_eq:NN \cOneFp \c_one_fp
+\fp_set_eq:NN \cInfFp \c_inf_fp
+\fp_set_eq:NN \cMinusInfFp \c_minus_inf_fp
+\fp_set_eq:NN \cEFp \c_e_fp
+\fp_set_eq:NN \cPiFp \c_pi_fp
+\fp_set_eq:NN \cOneDegreeFp \c_one_degree_fp
+
+\fp_new:N \lTmpaFp \fp_new:N \lTmpbFp \fp_new:N \lTmpcFp
+\fp_new:N \lTmpiFp \fp_new:N \lTmpjFp \fp_new:N \lTmpkFp
+\fp_new:N \l@Funx@Fp \fp_new:N \l@Funy@Fp \fp_new:N \l@Funz@Fp
+
+\fp_new:N \gTmpaFp \fp_new:N \gTmpbFp \fp_new:N \gTmpcFp
+\fp_new:N \gTmpiFp \fp_new:N \gTmpjFp \fp_new:N \gTmpkFp
+\fp_new:N \g@Funx@Fp \fp_new:N \g@Funy@Fp \fp_new:N \g@Funz@Fp
+
+\PrgNewFunction \FpEval { m }
{
- \int_step_variable:nnnNn { #1 } { #2 } { #3 } #4 { #5 }
+ \Result { \Expand { \fp_eval:n { #1 } } }
}
-\PrgNewConditional \IntCompare { m N m }
+\PrgNewFunction \FpMathAdd { m m }
{
- \int_compare:nNnTF {#1} #2 {#3}
+ \fp_set:Nn \l@Funx@Fp { \fp_eval:n { (#1) + (#2) } }
+ \Result { \FpUse \l@Funx@Fp }
+ }
+
+\PrgNewFunction \FpMathSub { m m }
+ {
+ \fp_set:Nn \l@Funx@Fp { \fp_eval:n { (#1) - (#2) } }
+ \Result { \FpUse \l@Funx@Fp }
+ }
+
+\PrgNewFunction \FpMathMult { m m }
+ {
+ \fp_set:Nn \l@Funx@Fp { \fp_eval:n { (#1) * (#2) } }
+ \Result { \FpUse \l@Funx@Fp }
+ }
+
+\PrgNewFunction \FpMathDiv { m m }
+ {
+ \fp_set:Nn \l@Funx@Fp { \fp_eval:n { (#1) / (#2) } }
+ \Result { \FpUse \l@Funx@Fp }
+ }
+
+\PrgNewFunction \FpMathSign { m }
+ {
+ \Result { \Expand { \fp_sign:n { #1 } } }
+ }
+
+\PrgNewFunction \FpMathAbs { m }
+ {
+ \Result { \Expand { \fp_abs:n { #1 } } }
+ }
+
+\PrgNewFunction \FpMathMax { m m }
+ {
+ \Result { \Expand { \fp_max:nn { #1 } { #2 } } }
+ }
+
+\PrgNewFunction \FpMathMin { m m }
+ {
+ \Result { \Expand { \fp_min:nn { #1 } { #2 } } }
+ }
+
+\PrgNewFunction \FpNew { M } { \fp_new:N #1 }
+
+\PrgNewFunction \FpConst { M m } { \fp_const:Nn #1 {#2} }
+
+\PrgNewFunction \FpUse { M } { \Result { \Expand { \fp_use:N #1 } } }
+
+\PrgNewFunction \FpLog { m } { \fp_log:n { #1 } }
+
+\PrgNewFunction \FpVarLog { M } { \fp_log:N #1 }
+
+\PrgNewFunction \FpShow { m } { \fp_show:n { #1 } }
+
+\PrgNewFunction \FpVarShow { M } { \fp_show:N #1 }
+
+\PrgNewFunction \FpSet { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \fp_gset:Nn #1 {#2} } { \fp_set:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \FpSetEq { M M }
+ {
+ \__fun_do_assignment:Nnn #1 { \fp_gset_eq:NN #1 #2 } { \fp_set_eq:NN #1 #2 }
+ }
+
+\PrgNewFunction \FpZero { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \fp_gzero:N #1 } { \fp_zero:N #1 }
+ }
+
+\PrgNewFunction \FpZeroNew { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \fp_gzero_new:N #1 } { \fp_zero_new:N #1 }
+ }
+
+\PrgNewFunction \FpAdd { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \fp_gadd:Nn #1 {#2} } { \fp_add:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \FpSub { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \fp_gsub:Nn #1 {#2} } { \fp_sub:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \FpStepInline { m m m n }
+ {
+ \fp_step_inline:nnnn { #1 } { #2 } { #3 } { #4 }
+ }
+
+\PrgNewFunction \FpStepVariable { m m m M n }
+ {
+ \fp_step_variable:nnnNn { #1 } { #2 } { #3 } #4 { #5 }
+ }
+
+\PrgNewConditional \FpIfExist { M }
+ {
+ \fp_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \FpCompare { m N m }
+ {
+ \fp_compare:nNnTF {#1} #2 {#3}
{ \Result { \cTrueBool } }
{ \Result { \cFalseBool } }
}
+%%% --------------------------------------------------------
+%%> \section{Interfaces for Dimensions (Dim)}
+%%% --------------------------------------------------------
+
+\cs_set_eq:NN \cMaxDim \c_max_dim
+\cs_set_eq:NN \cZeroDim \c_zero_dim
+
+\dim_new:N \lTmpaDim \dim_new:N \lTmpbDim \dim_new:N \lTmpcDim
+\dim_new:N \lTmpiDim \dim_new:N \lTmpjDim \dim_new:N \lTmpkDim
+\dim_new:N \l@Funx@Dim \dim_new:N \l@Funy@Dim \dim_new:N \l@Funz@Dim
+
+\dim_new:N \gTmpaDim \dim_new:N \gTmpbDim \dim_new:N \gTmpcDim
+\dim_new:N \gTmpiDim \dim_new:N \gTmpjDim \dim_new:N \gTmpkDim
+\dim_new:N \g@Funx@Dim \dim_new:N \g@Funy@Dim \dim_new:N \g@Funz@Dim
+
+\PrgNewFunction \DimEval { m }
+ {
+ \Result { \Expand { \dim_eval:n { #1 } } }
+ }
+
+\PrgNewFunction \DimMathAdd { m m }
+ {
+ \dim_set:Nn \l@Funx@Dim { \dim_eval:n { (#1) + (#2) } }
+ \Result { \Value \l@Funx@Dim }
+ }
+
+\PrgNewFunction \DimMathSub { m m }
+ {
+ \dim_set:Nn \l@Funx@Dim { \dim_eval:n { (#1) - (#2) } }
+ \Result { \Value \l@Funx@Dim }
+ }
+
+\PrgNewFunction \DimMathSign { m }
+ {
+ \Result { \Expand { \dim_sign:n { #1 } } }
+ }
+
+\PrgNewFunction \DimMathAbs { m }
+ {
+ \Result { \Expand { \dim_abs:n { #1 } } }
+ }
+
+\PrgNewFunction \DimMathMax { m m }
+ {
+ \Result { \Expand { \dim_max:nn { #1 } { #2 } } }
+ }
+
+\PrgNewFunction \DimMathMin { m m }
+ {
+ \Result { \Expand { \dim_min:nn { #1 } { #2 } } }
+ }
+
+\PrgNewFunction \DimMathRatio { m m }
+ {
+ \Result { \Expand { \dim_ratio:nn { #1 } { #2 } } }
+ }
+
+\PrgNewFunction \DimNew { M } { \dim_new:N #1 }
+
+\PrgNewFunction \DimConst { M m } { \dim_const:Nn #1 {#2} }
+
+\PrgNewFunction \DimUse { M } { \Result { \Value #1 } }
+
+\PrgNewFunction \DimLog { m } { \dim_log:n { #1 } }
+
+\PrgNewFunction \DimVarLog { M } { \dim_log:N #1 }
+
+\PrgNewFunction \DimShow { m } { \dim_show:n { #1 } }
+
+\PrgNewFunction \DimVarShow { M } { \dim_show:N #1 }
+
+\PrgNewFunction \DimSet { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \dim_gset:Nn #1 {#2} } { \dim_set:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \DimSetEq { M M }
+ {
+ \__fun_do_assignment:Nnn #1 { \dim_gset_eq:NN #1 #2 } { \dim_set_eq:NN #1 #2 }
+ }
+
+\PrgNewFunction \DimZero { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \dim_gzero:N #1 } { \dim_zero:N #1 }
+ }
+
+\PrgNewFunction \DimZeroNew { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \dim_gzero_new:N #1 } { \dim_zero_new:N #1 }
+ }
+
+\PrgNewFunction \DimAdd { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \dim_gadd:Nn #1 {#2} } { \dim_add:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \DimSub { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \dim_gsub:Nn #1 {#2} } { \dim_sub:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \DimStepInline { m m m n }
+ {
+ \dim_step_inline:nnnn { #1 } { #2 } { #3 } { #4 }
+ }
+
+\PrgNewFunction \DimStepVariable { m m m M n }
+ {
+ \dim_step_variable:nnnNn { #1 } { #2 } { #3 } #4 { #5 }
+ }
+
+\PrgNewConditional \DimIfExist { M }
+ {
+ \dim_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \DimCompare { m N m }
+ {
+ \dim_compare:nNnTF {#1} #2 {#3}
+ { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewFunction \DimCase { m m } { \dim_case:nn {#1} {#2} }
+\PrgNewFunction \DimCaseT { m m n } { \dim_case:nnT {#1} {#2} {#3} }
+\PrgNewFunction \DimCaseF { m m n } { \dim_case:nnF {#1} {#2} {#3} }
+\PrgNewFunction \DimCaseTF { m m n n } { \dim_case:nnTF {#1} {#2} {#3} {#4} }
+
+%%% --------------------------------------------------------
+%%> \section{Interfaces for Sorting Functions (Sort)}
+%%% --------------------------------------------------------
+
+\cs_set_eq:NN \SortReturnSame \sort_return_same:
+\cs_set_eq:NN \SortReturnSwapped \sort_return_swapped:
+
+%%% --------------------------------------------------------
+%%> \section{Interfaces for Comma Separated Lists (Clist)}
+%%% --------------------------------------------------------
+
+\clist_new:N \lTmpaClist \clist_new:N \lTmpbClist \clist_new:N \lTmpcClist
+\clist_new:N \lTmpiClist \clist_new:N \lTmpjClist \clist_new:N \lTmpkClist
+\clist_new:N \l@Funx@Clist \clist_new:N \l@Funy@Clist \clist_new:N \l@Funz@Clist
+
+\clist_new:N \gTmpaClist \clist_new:N \gTmpbClist \clist_new:N \gTmpcClist
+\clist_new:N \gTmpiClist \clist_new:N \gTmpjClist \clist_new:N \gTmpkClist
+\clist_new:N \g@Funx@Clist \clist_new:N \g@Funy@Clist \clist_new:N \g@Funz@Clist
+
+\clist_set_eq:NN \cEmptyClist \c_empty_clist
+
+\PrgNewFunction \ClistNew { M } { \clist_new:N #1 }
+
+\PrgNewFunction \ClistLog { m } { \clist_log:n { #1 } }
+
+\PrgNewFunction \ClistVarLog { M } { \clist_log:N #1 }
+
+\PrgNewFunction \ClistShow { m } { \clist_show:n { #1 } }
+
+\PrgNewFunction \ClistVarShow { M } { \clist_show:N #1 }
+
+\PrgNewFunction \ClistVarJoin { M m }
+ {
+ \Expand { \clist_use:Nn #1 { #2 } }
+ }
+
+\PrgNewFunction \ClistVarJoinExtended { M m m m }
+ {
+ \Expand { \clist_use:Nnnn #1 { #2 } { #3 } { #4 } }
+ }
+
+\PrgNewFunction \ClistJoin { m m }
+ {
+ \Expand { \clist_use:nn { #1 } { #2 } }
+ }
+
+\PrgNewFunction \ClistJoinExtended { m m m m }
+ {
+ \Expand { \clist_use:nnnn { #1 } { #2 } { #3 } { #4 } }
+ }
+
+\PrgNewFunction \ClistConst { M m } { \clist_const:Nn #1 { #2 } }
+
+\PrgNewFunction \ClistSet { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gset:Nn #1 {#2} } { \clist_set:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \ClistSetEq { M M }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gset_eq:NN #1 #2 } { \clist_set_eq:NN #1 #2 }
+ }
+
+\PrgNewFunction \ClistSetFromSeq { M M }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gset_from_seq:NN #1 #2 } { \clist_set_from_seq:NN #1 #2 }
+ }
+
+\PrgNewFunction \ClistConcat { M M M }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gconcat:NNN #1 #2 #3 } { \clist_concat:NNN #1 #2 #3 }
+ }
+
+\PrgNewFunction \ClistClear { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \clist_gclear:N #1 } { \clist_clear:N #1 }
+ }
+
+\PrgNewFunction \ClistClearNew { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \clist_gclear_new:N #1 } { \clist_clear_new:N #1 }
+ }
+
+\PrgNewFunction \ClistPutLeft { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gput_left:Nn #1 {#2} } { \clist_put_left:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \ClistPutRight { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gput_right:Nn #1 {#2} } { \clist_put_right:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \ClistRemoveDuplicates { M }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gremove_duplicates:N #1 } { \clist_remove_duplicates:N #1 }
+ }
+
+\PrgNewFunction \ClistRemoveAll { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gremove_all:Nn #1 {#2} } { \clist_remove_all:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \ClistReverse { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \clist_greverse:N #1 } { \clist_reverse:N #1 }
+ }
+
+\PrgNewFunction \ClistSort { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gsort:Nn #1 {#2} } { \clist_sort:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \ClistCount { m }
+ {
+ \Result { \Expand { \clist_count:n { #1 } } }
+ }
+
+\PrgNewFunction \ClistVarCount { m }
+ {
+ \Result { \Expand { \clist_count:N #1 } }
+ }
+
+\PrgNewFunction \ClistGet { M M } { \clist_get:NN #1 #2 }
+\PrgNewFunction \ClistGetT { M M n } { \clist_get:NNT #1 #2 {#3} }
+\PrgNewFunction \ClistGetF { M M n } { \clist_get:NNF #1 #2 {#3} }
+\PrgNewFunction \ClistGetTF { M M n n } { \clist_get:NNTF #1 #2 {#3} {#4} }
+
+\PrgNewFunction \ClistPop { M M }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gpop:NN #1 #2 } { \clist_pop:NN #1 #2 }
+ }
+\PrgNewFunction \ClistPopT { M M n }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gpop:NNT #1 #2 {#3} } { \clist_pop:NNT #1 #2 {#3} }
+ }
+\PrgNewFunction \ClistPopF { M M n }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gpop:NNF #1 #2 {#3} } { \clist_pop:NNF #1 #2 {#3} }
+ }
+\PrgNewFunction \ClistPopTF { M M n n }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gpop:NNTF #1 #2 {#3} {#4} } { \clist_pop:NNTF #1 #2 {#3} {#4} }
+ }
+
+\PrgNewFunction \ClistPush { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \clist_gpush:Nn #1 {#2} } { \clist_push:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \ClistItem { m m } { \Expand { \clist_item:nn {#1} {#2} } }
+
+\PrgNewFunction \ClistVarItem { M m } { \Expand { \clist_item:Nn #1 {#2} } }
+
+\PrgNewFunction \ClistRandItem { m } { \Expand { \clist_rand_item:n {#1} } }
+
+\PrgNewFunction \ClistVarRandItem { M } { \Expand { \clist_rand_item:N #1 } }
+
+\PrgNewFunction \ClistMapInline { m n }
+ {
+ \clist_map_inline:nn {#1} {#2}
+ }
+
+\PrgNewFunction \ClistVarMapInline { M n }
+ {
+ \clist_map_inline:Nn #1 {#2}
+ }
+
+\PrgNewFunction \ClistMapVariable { m M n }
+ {
+ \clist_map_variable:nNn {#1} #2 {#3}
+ }
+
+\PrgNewFunction \ClistVarMapVariable { M M n }
+ {
+ \clist_map_variable:NNn #1 #2 {#3}
+ }
+
+\cs_set_eq:NN \ClistMapBreak \clist_map_break:
+
+\PrgNewConditional \ClistIfExist { M }
+ {
+ \clist_if_exist:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \ClistIfEmpty { m }
+ {
+ \clist_if_empty:nTF {#1} { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \ClistVarIfEmpty { m }
+ {
+ \clist_if_empty:NTF #1 { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \ClistIfIn { m m }
+ {
+ \clist_if_in:nnTF {#1} {#2}
+ { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \ClistVarIfIn { M m }
+ {
+ \clist_if_in:NnTF #1 {#2}
+ { \Result { \cTrueBool } } { \Result { \cFalseBool } }
+ }
+
diff --git a/macros/latex/contrib/functional/functional.tex b/macros/latex/contrib/functional/functional.tex
index 18dfa30662..b3eb028adc 100644
--- a/macros/latex/contrib/functional/functional.tex
+++ b/macros/latex/contrib/functional/functional.tex
@@ -1,9 +1,9 @@
-% -*- coding: utf-8 -*-
-
+% -*- coding: utf-8 -*-
+% !TEX program = lualatex
\documentclass[oneside]{book}
\usepackage[a4paper,margin=2.5cm]{geometry}
-\newcommand*{\myversion}{2022A}
+\newcommand*{\myversion}{2022B}
\newcommand*{\mydate}{Version \myversion\ (\the\year-\mylpad\month-\mylpad\day)}
\newcommand*{\mylpad}[1]{\ifnum#1<10 0\the#1\else\the#1\fi}
@@ -18,6 +18,8 @@
\NewCodeHighEnv{code}{style/main=gray9,style/code=gray9}
\NewCodeHighEnv{demo}{style/main=gray9,style/code=gray9,demo}
+\usepackage{enumitem}
+
\NewDocumentCommand\MySubScript{m}{$_{#1}$}
\ExplSyntaxOn
@@ -34,13 +36,13 @@
}
\ExplSyntaxOff
-\NewDocumentEnvironment{variable}{m}{
+\NewDocumentEnvironment{variable}{om}{
\vspace{5pt}
\begin{minipage}{\linewidth}
\hrule\vspace{4pt}\obeylines%
\begingroup
\ttfamily\bfseries\color{azure3}
- \PrintVarList{#1}
+ \PrintVarList{#2}
\endgroup
\par\vspace{4pt}\hrule
\end{minipage}\par\nopagebreak\vspace{4pt}
@@ -48,7 +50,7 @@
\vspace{5pt}%
}
-\NewDocumentEnvironment{function}{m}{
+\NewDocumentEnvironment{function}{om}{
\vspace{5pt}%
}{\vspace{5pt}}
@@ -74,6 +76,9 @@
\texttt{\{}\textsl{$\langle$\ignorespaces\lTmpaTl\unskip$\rangle$}\texttt{\}}%
}
+\NewDocumentCommand\nan{}{\texttt{NaN}}
+\NewDocumentCommand\enquote{m}{``#1''}
+
\let\tn=\cs
\RenewDocumentCommand\emph{m}{%
@@ -92,7 +97,7 @@
\begin{document}
-\title{\sffamily LaTeX2 \textcolor{green3}{Functional} Interfaces to LaTeX3 Programming Layer}
+\title{\sffamily LaTeX2 \textcolor{green3}{Functional} Interfaces for LaTeX3 Programming Layer}
\author{Jianrui Lyu (tolvjr@163.com)\\\url{https://github.com/lvjr/functional}}
\date{\mydate\vspace{1cm}\\\myabstract\vspace{10cm}}
@@ -120,44 +125,48 @@ Note that many paragraphs in this manual are copied from the documentation of \t
We will compare our first example with a similar \verb!Lua! example:
-\begin{code}
--- lua code --
-function MathSquare (arg)
- local lTmpaInt = arg * arg
- return lTmpaInt
-end
-print(MathSquare(5))
-print(MathSquare(MathSquare(5)))
-\end{code}
-
+\begin{minipage}{0.55\textwidth}
\begin{codehigh}
%% function code
-\ExplSyntaxOn
+\IgnoreSpacesOn
\PrgNewFunction \MathSquare { m } {
- \IntSet \lTmpaInt { \IntEval { #1 * #1 } }
+ \IntSet \lTmpaInt { \IntEval {#1 * #1} }
\Result { \Value \lTmpaInt }
}
-\ExplSyntaxOff
+\IgnoreSpacesOff
\MathSquare{5}
\MathSquare{\MathSquare{5}}
\end{codehigh}
+\end{minipage}%
+\begin{minipage}{0.45\textwidth}
+\begin{code}
+-- define a function --
+function MathSquare (arg)
+ local lTmpaInt = arg * arg
+ return lTmpaInt
+end
+-- use the function --
+print(MathSquare(5))
+print(MathSquare(MathSquare(5)))
+\end{code}
+\end{minipage}
-%\ExplSyntaxOn
+%\IgnoreSpacesOn
%\PrgNewFunction \MathSquare { m }{
% \IntSet \lTmpaInt { \IntEval { #1 * #1 } }
% \Result { \Value \lTmpaInt }
%}
-%\ExplSyntaxOff
+%\IgnoreSpacesOff
%\MathSquare{5}
%\MathSquare{\MathSquare{5}}
-%\ExplSyntaxOn
+%\IgnoreSpacesOn
%\PrgNewFunction \MathCubic { m }
% {
% \IntSet \lTmpaInt { \IntEval { #1 * #1 * #1 } }
% \Result { \Value \lTmpaInt }
% }
-%\ExplSyntaxOff
+%\IgnoreSpacesOff
%\MathCubic{2}
%\MathCubic{\MathCubic{2}}
@@ -176,38 +185,42 @@ with \cs{Result} command. And \verb!functional! package is responsible for
inserting result tokens to the input stream at the appropriate time.
To remove space tokens inside function code in defining functions,
-you'd better put function definitions inside \verb!\ExplSyntaxOn! and
-\verb!\ExplSyntaxOff! block. Within this block, \verb!~! is used to input a space.
+you'd better put function definitions inside \verb!\IgnoreSpacesOn! and
+\verb!\IgnoreSpacesOff! block. Within this block, \verb!~! is used to input a space.
At the end of this section,
we will compare our factorial example with a similar \verb!Lua! example:
-\begin{code}
--- lua code --
-function Factorial (n)
- if n == 0 then
- return 1
- else
- return n * Factorial(n-1)
- end
-end
-print(Factorial(4))
-\end{code}
-
+\begin{minipage}{0.69\textwidth}
\begin{codehigh}
-\ExplSyntaxOn
-\PrgNewFunction \Factorial { m } {
+\IgnoreSpacesOn
+\PrgNewFunction \Fact { m } {
\IntCompareTF {#1} = {0} {
\Result {1}
}{
- \Result { \IntMathMult {#1} { \Factorial { \IntMathSub{#1}{1} } } }
+ \Result {\IntMathMult{#1}{\Fact{\IntMathSub{#1}{1}}}}
}
}
-\ExplSyntaxOff
-\Factorial{4}
+\IgnoreSpacesOff
+\Fact{4}
\end{codehigh}
+\end{minipage}%
+\begin{minipage}{0.31\textwidth}
+\begin{code}
+-- define a function --
+function Fact (n)
+ if n == 0 then
+ return 1
+ else
+ return n * Fact(n-1)
+ end
+end
+-- use the function --
+print(Fact(4))
+\end{code}
+\end{minipage}
-%\ExplSyntaxOn
+%\IgnoreSpacesOn
%\PrgNewFunction \Factorial { m } {
% \IntCompareTF {#1} = {0} {
% \Result {1}
@@ -215,7 +228,7 @@ print(Factorial(4))
% \Result { \IntMathMult {#1} { \Factorial { \IntMathSub{#1}{1} } } }
% }
%}
-%\ExplSyntaxOff
+%\IgnoreSpacesOff
%\Factorial{0}
%\Factorial{4}
@@ -223,47 +236,50 @@ print(Factorial(4))
In \verb!Lua! language, a function or a condition expression makes a block,
and the values of local variables will be reset after a block.
-For example
-
-\begin{code}
--- lua code --
-local a = 1
-print(a) ---- 1
-function SomeFun()
- local a = 2
- print(a) ---- 2
- if 1 > 0 then
- local a = 3
- print(a) ---- 3
- end
- print(a) ---- 2
-end
-SomeFun()
-print(a) ---- 1
-\end{code}
-
In \verb!functional! package, a condition expression is in fact a function,
and you can make every function become a group by setting
\verb!\Functional{scoping=true}!. For example
+\begin{minipage}{0.58\textwidth}
\begin{codehigh}
\Functional{scoping=true}
-\ExplSyntaxOn
+\IgnoreSpacesOn
\IntSet \lTmpaInt {1}
-\IntLog \lTmpaInt % ---- 1
+\IntLogVar \lTmpaInt % ---- 1
\PrgNewFunction \SomeFun { } {
\IntSet \lTmpaInt {2}
- \IntLog \lTmpaInt % ---- 2
+ \IntLogVar \lTmpaInt % ---- 2
\IntCompareTF {1} > {0} {
\IntSet \lTmpaInt {3}
- \IntLog \lTmpaInt % ---- 3
+ \IntLogVar \lTmpaInt % ---- 3
}{ }
- \IntLog \lTmpaInt % ---- 2
+ \IntLogVar \lTmpaInt % ---- 2
}
\SomeFun
-\IntLog \lTmpaInt % ---- 1
-\ExplSyntaxOff
+\IntLogVar \lTmpaInt % ---- 1
+\IgnoreSpacesOff
\end{codehigh}
+\end{minipage}%
+\begin{minipage}{0.42\textwidth}
+\begin{code}
+-- lua code --
+-- begin example --
+local a = 1
+print(a) ---- 1
+function SomeFun()
+ local a = 2
+ print(a) ---- 2
+ if 1 > 0 then
+ local a = 3
+ print(a) ---- 3
+ end
+ print(a) ---- 2
+end
+SomeFun()
+print(a) ---- 1
+-- end example --
+\end{code}
+\end{minipage}
Same as \verb!expl3!, the names of local variables \emph{must} start with \verb!l!,
while names of global variables \emph{must} start with \verb!g!.
@@ -275,22 +291,46 @@ by checking leading letters of their names. So for integer variables, you can wr
The previous example will produce different result
if we change variable from \verb!\lTmpaInt! to \verb!\gTmpaInt!.
+\begin{minipage}{0.58\textwidth}
\begin{codehigh}
\Functional{scoping=true}
+\IgnoreSpacesOn
\IntSet \gTmpaInt {1}
-\IntLog \gTmpaInt % ---- 1
+\IntLogVar \gTmpaInt % ---- 1
\PrgNewFunction \SomeFun { } {
\IntSet \gTmpaInt {2}
- \IntLog \gTmpaInt % ---- 2
+ \IntLogVar \gTmpaInt % ---- 2
\IntCompareTF {1} > {0} {
\IntSet \gTmpaInt {3}
- \IntLog \gTmpaInt % ---- 3
+ \IntLogVar \gTmpaInt % ---- 3
}{ }
- \IntLog \gTmpaInt % ---- 3
+ \IntLogVar \gTmpaInt % ---- 3
}
\SomeFun
-\IntLog \gTmpaInt % ---- 3
+\IntLogVar \gTmpaInt % ---- 3
+\IgnoreSpacesOff
\end{codehigh}
+\end{minipage}%
+\begin{minipage}{0.42\textwidth}
+\begin{code}
+-- lua code --
+-- begin example --
+a = 1
+print(a) ---- 1
+function SomeFun()
+ a = 2
+ print(a) ---- 2
+ if 1 > 0 then
+ a = 3
+ print(a) ---- 3
+ end
+ print(a) ---- 3
+end
+SomeFun()
+print(a) ---- 3
+-- end example --
+\end{code}
+\end{minipage}
As you can see, the values of global variables will never be reset after a group.
@@ -326,9 +366,9 @@ For example, the tracing log of the first example in this chapter will be the fo
[I] \Result{25}
[O] 25
[O] 25
- [I] \IntSet\lTmpaInt {25}
- [O]
- [I] \Value\lTmpaInt
+ [I] \IntSet{\lTmpaInt }{25}
+ [O]
+ [I] \Value{\lTmpaInt }
[O] 25
[I] \Result{25}
[O] 25
@@ -340,9 +380,9 @@ For example, the tracing log of the first example in this chapter will be the fo
[I] \Result{625}
[O] 625
[O] 625
- [I] \IntSet\lTmpaInt {625}
- [O]
- [I] \Value\lTmpaInt
+ [I] \IntSet{\lTmpaInt }{625}
+ [O]
+ [I] \Value{\lTmpaInt }
[O] 625
[I] \Result{625}
[O] 625
@@ -354,16 +394,22 @@ For example, the tracing log of the first example in this chapter will be the fo
Within \verb!expl3!, there are eight commands for defining new functions,
which is good for power users.
+\begin{minipage}{0.5\textwidth}
\begin{code}[language=latex/latex3]
\cs_new:Npn
\cs_new_nopar:Npn
\cs_new_protected:Npn
\cs_new_protected_nopar:Npn
+\end{code}
+\end{minipage}%
+\begin{minipage}{0.5\textwidth}
+\begin{code}[language=latex/latex3]
\cs_new:Nn
\cs_new_nopar:Nn
\cs_new_protected:Nn
\cs_new_protected_nopar:Nn
\end{code}
+\end{minipage}
Within \verb!functional! package, there is only one command (\cs{PrgNewFunction})
for defining new functions, which is good for normal users.
@@ -377,6 +423,7 @@ Since \verb!functional! package gets the results of functions by evaluation
Within \verb!expl3!, there are several expansion variants for arguments,
and many expansion functions for expanding them, which are necessary for power users.
+\begin{minipage}{0.5\textwidth}
\begin{code}[language=latex/latex3]
\module_foo:c
\module_bar:e
@@ -386,7 +433,8 @@ and many expansion functions for expanding them, which are necessary for power u
\module_bar:V
\module_bar:v
\end{code}
-
+\end{minipage}%
+\begin{minipage}{0.5\textwidth}
\begin{code}[language=latex/latex3]
\exp_args:Nc
\exp_args:Ne
@@ -396,6 +444,7 @@ and many expansion functions for expanding them, which are necessary for power u
\exp_args:NV
\exp_args:Nv
\end{code}
+\end{minipage}
Within \verb!functional! package, there are only three variants
(\verb!c!, \verb!e!, \verb!V!) are provided, and these variants are defined
@@ -426,7 +475,7 @@ simply composing \cs{Name} and \cs{Value} functions:
\Value{\Name{lTmpaInt}}
\end{demohigh}
-\chapter{Basic Definitions (\texttt{l3basics})}
+\chapter{Functional Progarmming (\texttt{Prg})}
\section{Defining Functions and Conditionals}
@@ -470,6 +519,8 @@ will be created at the same time. \verb!\FooIfBarTF! function has two extra argu
which are \Arg{true code} and \Arg{false code}.\par
\end{function}
+\section{Collecting Returned Values}
+
\begin{function}{\Result}
\begin{syntax}
\cs{Result} \Arg{tokens}
@@ -478,7 +529,9 @@ Appends \meta{tokens} to \verb!\gResultTl!, which holds the returned value of cu
This function is normally used in the \meta{code} of \cs{PrgNewFunction} and \cs{PrgNewConditional}.
\end{function}
-\section{Expanding and Using Tokens}
+\chapter{Argument Using (\texttt{Use})}
+
+\section{Expanding Tokens}
\begin{function}{\Name}
\begin{syntax}
@@ -538,6 +591,8 @@ Recovers the content of the \meta{variable}, then prevents expansion
of this material inside the argument of \cs{Expand} function.
\end{function}
+\section{Using Tokens}
+
\begin{function}{\UseOne,\GobbleOne}
\begin{syntax}
\cs{UseOne} \Arg{argument}
@@ -578,9 +633,18 @@ For example
\end{demohigh}
\end{function}
-\chapter{Control Structures (\texttt{l3prg})}
+\chapter{Control Structures (\texttt{Bool})}
+
+\section{Constant and Scratch Booleans}
-\section{Scratch Variables of Booleans}
+\begin{variable}{\cTrueBool,\cFalseBool}
+Constants that represent \verb|true| and \verb|false|, respectively. Used to
+implement predicates. For example
+\begin{demohigh}
+\BoolVarIfTF \cTrueBool {\Result{True!}} {\Result{False!}}
+\BoolVarIfTF \cFalseBool {\Result{True!}} {\Result{False!}}
+\end{demohigh}
+\end{variable}
\begin{variable}{\lTmpaBool,\lTmpbBool,\lTmpcBool,\lTmpiBool,\lTmpjBool,\lTmpkBool}
Scratch booleans for local assignment. These are never used by
@@ -596,10 +660,7 @@ function. However, they may be overwritten by other
code and so should only be used for short-term storage.
\end{variable}
-%\BoolIfTF\cTrueBool{\Result{true}}{\Result{false}}
-%\BoolIfTF\cFalseBool{\Result{true}}{\Result{false}}
-
-\section{Public Functions for Booleans}
+\section{Creating and Setting Booleans}
\begin{function}{\BoolNew}
\begin{syntax}
@@ -610,6 +671,33 @@ name is already taken. The declaration is global. The
\meta{boolean} is initially \texttt{false}.
\end{function}
+\begin{function}{\BoolConst}
+\begin{syntax}
+\cs{BoolConst} \meta{boolean} \Arg{boolexpr}
+\end{syntax}
+Creates a new constant \meta{boolean} or raises an error if the name
+is already taken. The value of the \meta{boolean} is set globally to
+the result of evaluating the \meta{boolexpr}.
+For example
+\begin{codehigh}
+\BoolConst \cFooSomeBool {\IntCompare{3}>{2}}
+\BoolVarLog \cFooSomeBool
+\end{codehigh}
+\end{function}
+
+\begin{function}{\BoolSet}
+\begin{syntax}
+\cs{BoolSet} \meta{boolean} \Arg{boolexpr}
+\end{syntax}
+Evaluates the \meta{boolean expression} and sets the \meta{boolean} variable to
+the logical truth of this evaluation.
+For example
+\begin{codehigh}
+\BoolSet \lTmpaBool {\IntCompare{3}<{2}}
+\BoolVarLog \lTmpaBool
+\end{codehigh}
+\end{function}
+
\begin{function}{\BoolSetTrue}
\begin{syntax}
\cs{BoolSetTrue} \meta{boolean}
@@ -624,24 +712,165 @@ Sets \meta{boolean} logically \texttt{true}.
Sets \meta{boolean} logically \texttt{false}.
\end{function}
-\begin{function}{\BoolIf,\BoolIfTF}
+\begin{function}{\BoolSetEq}
+\begin{syntax}
+\cs{BoolSetEq} \meta{boolean_1} \meta{boolean_2}
+\end{syntax}
+Sets \meta{boolean_1} to the current value of \meta{boolean_2}.
+For example
+\begin{codehigh}
+\BoolSetTrue \lTmpaBool
+\BoolSetEq \lTmpbBool \lTmpaBool
+\BoolVarLog \lTmpbBool
+\end{codehigh}
+\end{function}
+
+\section{Viewing Booleans}
+
+\begin{function}{\BoolLog}
+\begin{syntax}
+\cs{BoolLog} \Arg{boolean expression}
+\end{syntax}
+Writes the logical truth of the \meta{boolean expression} in the log file.
+\end{function}
+
+\begin{function}{\BoolVarLog}
+\begin{syntax}
+\cs{BoolVarLog} \meta{boolean}
+\end{syntax}
+Writes the logical truth of the \meta{boolean} in the log file.
+\end{function}
+
+\begin{function}{\BoolShow}
+\begin{syntax}
+\cs{BoolShow} \Arg{boolean expression}
+\end{syntax}
+Displays the logical truth of the \meta{boolean expression} on the terminal.
+\end{function}
+
+\begin{function}{\BoolVarShow}
+\begin{syntax}
+\cs{BoolVarShow} \meta{boolean}
+\end{syntax}
+Displays the logical truth of the \meta{boolean} on the terminal.
+\end{function}
+
+\section{Booleans and Conditionals}
+
+\begin{function}{\BoolIfExist,\BoolIfExistTF}
+\begin{syntax}
+\cs{BoolIfExist} \meta{boolean}
+\cs{BoolIfExistTF} \meta{boolean} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests whether the \meta{boolean} is currently defined. This does not
+check that the \meta{boolean} really is a boolean variable.
+For example
+\begin{demohigh}
+\BoolIfExistTF \lTmpaBool {\Result{Yes}} {\Result{No}}
+\BoolIfExistTF \lFooUndefinedBool {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\BoolVarIf,\BoolVarIfTF}
\begin{syntax}
-\cs{BoolIf} \meta{boolean}
-\cs{BoolIfTF} \meta{boolean} \Arg{true code} \Arg{false code}
+\cs{BoolVarIf} \meta{boolean}
+\cs{BoolVarIfTF} \meta{boolean} \Arg{true code} \Arg{false code}
\end{syntax}
Tests the current truth of \meta{boolean}, and continues evaluation
based on this result. For example
\begin{demohigh}
-\BoolSetTrue\lTmpaBool
-\BoolIfTF\lTmpaBool{\Result{True!}}{\Result{False!}}
-\BoolSetFalse\lTmpaBool
-\BoolIfTF\lTmpaBool{\Result{True!}}{\Result{False!}}
+\BoolSetTrue \lTmpaBool
+\BoolVarIfTF \lTmpaBool {\Result{True!}} {\Result{False!}}
+\BoolSetFalse \lTmpaBool
+\BoolVarIfTF \lTmpaBool {\Result{True!}} {\Result{False!}}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\BoolVarNot,\BoolVarNotTF}
+\begin{syntax}
+\cs{BoolVarNot} \meta{boolean}
+\cs{BoolVarNotTF} \meta{boolean} \Arg{true code} \Arg{false code}
+\end{syntax}
+Evaluates \meta{true code} if \meta{boolean} is \verb!false!,
+and \meta{false code} If \meta{boolean} is \verb!true!.
+For example
+\begin{demohigh}
+\BoolVarNotTF {\IntCompare{3}>{2}} {\Result{Yes}} {\Result{No}}
\end{demohigh}
\end{function}
-\chapter{Token Lists (\texttt{l3tl})}
+\begin{function}{\BoolVarAnd,\BoolVarAndTF}
+\begin{syntax}
+\cs{BoolVarAnd} \meta{boolean_1} \meta{boolean_2}
+\cs{BoolVarAndTF} \meta{boolean_1} \meta{boolean_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Implements the \enquote{And} operation between two booleans,
+hence is \texttt{true} if both are \texttt{true}.
+%Contrarily to the infix operator \verb|&&|,
+The \meta{boolean_2} is only evaluated if it is needed to determine the result of
+\cs{BoolVarAnd}.
+For example
+\begin{demohigh}
+\BoolVarAndTF {\IntCompare{3}>{2}} {\IntCompare{3}>{4}} {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\BoolVarOr,\BoolVarOrTF}
+\begin{syntax}
+\cs{BoolVarOr} \meta{boolean_1} \meta{boolean_2}
+\cs{BoolVarOrTF} \meta{boolean_1} \meta{boolean_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Implements the \enquote{Or} operation between two booleans,
+hence is \texttt{true} if either one is \texttt{true}.
+%Contrarily to the infix operator \verb"||",
+The \meta{boolean_2} is only evaluated if it is needed to determine the result of
+\cs{BoolVarOr}.
+For example
+\begin{demohigh}
+\BoolVarOrTF {\IntCompare{3}>{2}} {\IntCompare{3}>{4}} {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\BoolVarXor,\BoolVarXorTF}
+\begin{syntax}
+\cs{BoolVarXor} \meta{boolean_1} \meta{boolean_2}
+\cs{BoolVarXorTF} \meta{boolean_1} \meta{boolean_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Implements an \enquote{exclusive or} operation between two booleans.
+For example
+\begin{demohigh}
+\BoolVarXorTF {\IntCompare{3}>{2}} {\IntCompare{3}>{4}} {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+\end{function}
-\section{Scratch Variables of Token Lists}
+\chapter{Token Lists (\texttt{Tl})}
+
+\section{Constant and Scratch Token Lists}
+
+\begin{variable}{\cSpaceTl}
+An explicit space character contained in a token list%
+%(compare this with \cs{c_space_token})
+. For use where an explicit space is required.
+\end{variable}
+
+\begin{variable}{\cEmptyTl}
+Constant that is always empty.
+\end{variable}
+
+%\begin{variable}{\cNoValueTl}
+%A marker for the absence of an argument. This constant \verb|tl| can safely
+%be typeset (\emph{cf.}~\cs{qNil}), with the result being \verb|-NoValue-|.
+%It is important to note that \cs{cNoValueTl} is constructed such that it
+%will \emph{not} match the simple text input \verb|-NoValue-|, \emph{i.e.}
+%that
+%\begin{demohigh}
+%\TlIfEqTF {\TlUse\cNoValueTl} {-NoValue-} {Result{Yes}} {\Result{No}}
+%\end{demohigh}
+%The \cs{cNoValueTl} marker is intended for
+%use in creating document-level interfaces, where it serves as an indicator
+%that an (optional) argument was omitted. In particular, it is distinct
+%from a simple empty \verb|tl|.
+%\end{variable}
\begin{variable}{\lTmpaTl,\lTmpbTl,\lTmpcTl,\lTmpiTl,\lTmpjTl,\lTmpkTl}
Scratch token lists for local assignment. These are never used by
@@ -657,17 +886,26 @@ function. However, they may be overwritten by other
code and so should only be used for short-term storage.
\end{variable}
-\section{Public Functions for Token Lists}
+\section{Creating and Using Token Lists}
\begin{function}{\TlNew}
\begin{syntax}
-\cs{TlNew} \meta{tl~var}
+\cs{TlNew} \meta{tl var}
\end{syntax}
-Creates a new \meta{tl~var} or raises an error if the
+Creates a new \meta{tl var} or raises an error if the
name is already taken. The declaration is global. The
\meta{tl~var} is initially empty.
\end{function}
+\begin{function}{\TlConst}
+\begin{syntax}
+\cs{TlConst} \meta{tl var} \Arg{token list}
+\end{syntax}
+Creates a new constant \meta{tl var} or raises an error
+if the name is already taken. The value of the
+\meta{tl var} is set globally to the \meta{token list}.
+\end{function}
+
\begin{function}{\TlUse}
\begin{syntax}
\cs{TlUse} \meta{tl~var}
@@ -678,6 +916,97 @@ does not exist or if it is invalid. Note that it is possible to use
a \meta{tl~var} directly without an accessor function.
\end{function}
+\begin{function}{\TlToStr}
+\begin{syntax}
+\cs{TlToStr} \Arg{token list}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string}, returning the
+resulting character tokens. A \meta{string}
+is a series of tokens with category code $12$ (other) with the exception
+of spaces, which retain category code $10$ (space).
+%This function requires only a single expansion.
+%Its argument \emph{must} be braced.
+%\begin{texnote}
+%This is the \eTeX{} primitive \tn{detokenize}.
+%Converting a \meta{token list} to a \meta{string} yields a
+%concatenation of the string representations of every token in the
+%\meta{token list}.
+%The string representation of a control sequence is
+%\begin{itemize}
+%\item an escape character, whose character code is given by the
+%internal parameter \tn{escapechar}, absent if the
+%\tn{escapechar} is negative or greater than the largest
+%character code;
+%\item the control sequence name, as defined by \cs{cs_to_str:N};
+%\item a space, unless the control sequence name is a single
+%character whose category at the time of expansion of
+%\cs{tl_to_str:n} is not \enquote{letter}.
+%\end{itemize}
+%The string representation of an explicit character token is that
+%character, doubled in the case of (explicit) macro parameter
+%characters (normally \verb|#|).
+%In particular, the string representation of a token list may
+%depend on the category codes in effect when it is evaluated, and
+%the value of the \tn{escapechar}: for instance |\tl_to_str:n {\a}|
+%normally produces the three character \enquote{backslash},
+%\enquote{lower-case a}, \enquote{space}, but it may also produce a
+%single \enquote{lower-case a} if the escape character is negative
+%and \texttt{a} is currently not a letter.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\TlVarToStr}
+\begin{syntax}
+\cs{TlVarToStr} \meta{tl var}
+\end{syntax}
+Converts the content of the \meta{tl var} to a string, returning the
+resulting character tokens. A \meta{string}
+is a series of tokens with category code $12$ (other) with the exception
+of spaces, which retain category code $10$ (space).
+\end{function}
+
+\section{Viewing Token Lists}
+
+\begin{function}{\TlLog}
+\begin{syntax}
+\cs{TlLog} \Arg{token list}
+\end{syntax}
+Writes the \meta{token list} in the log file. See also
+\cs{TlShow} which displays the result in the terminal.
+\end{function}
+
+\begin{function}{\TlVarLog}
+\begin{syntax}
+\cs{TlVarLog} \meta{tl var}
+\end{syntax}
+Writes the content of the \meta{tl var} in the log file. See also
+\cs{TlVarShow} which displays the result in the terminal.
+\end{function}
+
+\begin{function}{\TlShow}
+\begin{syntax}
+\cs{TlShow} \Arg{token list}
+\end{syntax}
+Displays the \meta{token list} on the terminal.
+%\begin{texnote}
+%This is similar to the \eTeX{} primitive \tn{showtokens}, wrapped
+%to a fixed number of characters per line.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\TlVarShow}
+\begin{syntax}
+\cs{TlVarShow} \meta{tl var}
+\end{syntax}
+Displays the content of the \meta{tl var} on the terminal.
+\begin{texnote}
+This is similar to the \TeX{} primitive \tn{show}, wrapped to a
+fixed number of characters per line.
+\end{texnote}
+\end{function}
+
+\section{Setting Token List Variables}
+
\begin{function}{\TlSet}
\begin{syntax}
\cs{TlSet} \meta{tl~var} \Arg{tokens}
@@ -685,24 +1014,50 @@ a \meta{tl~var} directly without an accessor function.
Sets \meta{tl~var} to contain \meta{tokens},
removing any previous content from the variable. For example
\begin{demohigh}
-\TlSet\lTmpiTl{\IntMathMult{4}{5}}
-\TlUse\lTmpiTl
+\TlSet \lTmpiTl {\IntMathMult{4}{5}}
+\TlUse \lTmpiTl
\end{demohigh}
\end{function}
+\begin{function}{\TlSetEq}
+\begin{syntax}
+\cs{TlSetEq} \meta{tl var_1} \meta{tl var_2}
+\end{syntax}
+Sets the content of \meta{tl var_1} equal to that of
+\meta{tl var_2}.
+\end{function}
+
\begin{function}{\TlClear}
\begin{syntax}
\cs{TlClear} \meta{tl~var}
\end{syntax}
Clears all entries from the \meta{tl~var}. For example
\begin{demohigh}
-\TlSet\lTmpjTl{One}
-\TlClear\lTmpjTl
-\TlSet\lTmpjTl{Two}
-\TlUse\lTmpjTl
+\TlSet \lTmpjTl {One}
+\TlClear \lTmpjTl
+\TlSet \lTmpjTl {Two}
+\TlUse \lTmpjTl
\end{demohigh}
\end{function}
+\begin{function}{\TlClearNew}
+\begin{syntax}
+\cs{TlClearNew} \meta{tl var}
+\end{syntax}
+Ensures that the \meta{tl var} exists globally by applying
+\cs{TlNew} if necessary, then applies \cs{TlClear} to leave
+the \meta{tl var} empty.
+\end{function}
+
+\begin{function}{\TlConcat}
+\begin{syntax}
+\cs{TlConcat} \meta{tl var_1} \meta{tl var_2} \meta{tl var_3}
+\end{syntax}
+Concatenates the content of \meta{tl var_2} and \meta{tl var_3}
+together and saves the result in \meta{tl var_1}. The \meta{tl var_2}
+is placed at the left side of the new token list.
+\end{function}
+
\begin{function}{\TlPutLeft}
\begin{syntax}
\cs{TlPutLeft} \meta{tl~var} \Arg{tokens}
@@ -710,9 +1065,9 @@ Clears all entries from the \meta{tl~var}. For example
Appends \meta{tokens} to the left side of the current content of
\meta{tl~var}. For example
\begin{demohigh}
-\TlSet\lTmpkTl{Functional}
-\TlPutLeft\lTmpkTl{Hello}
-\TlUse\lTmpkTl
+\TlSet \lTmpkTl {Functional}
+\TlPutLeft \lTmpkTl {Hello}
+\TlUse \lTmpkTl
\end{demohigh}
\end{function}
@@ -723,49 +1078,1233 @@ Appends \meta{tokens} to the left side of the current content of
Appends \meta{tokens} to the right side of the current content of
\meta{tl~var}. For example
\begin{demohigh}
-\TlSet\lTmpkTl{Functional}
-\TlPutRight\lTmpkTl{World}
-\TlUse\lTmpkTl
+\TlSet \lTmpkTl {Functional}
+\TlPutRight \lTmpkTl {World}
+\TlUse \lTmpkTl
+\end{demohigh}
+\end{function}
+
+\section{Replacing Tokens}
+
+Within token lists, replacement takes place at the top level: there is
+no recursion into brace groups (more precisely, within a group defined by
+a categroy code $1$/$2$ pair).
+
+\begin{function}{\TlReplaceOnce}
+\begin{syntax}
+\cs{TlReplaceOnce} \meta{tl var} \Arg{old tokens} \Arg{new tokens}
+\end{syntax}
+Replaces the first (leftmost) occurrence of \meta{old tokens} in the
+\meta{tl var} with \meta{new tokens}. \meta{Old tokens}
+cannot contain \verb|{|, \verb|}| or \verb|#|
+(more precisely, explicit character tokens with category code $1$
+(begin-group) or $2$ (end-group), and tokens with category code $6$).
+\end{function}
+
+\begin{function}{\TlReplaceAll}
+\begin{syntax}
+\cs{TlReplaceAll} \meta{tl var} \Arg{old tokens} \Arg{new tokens}
+\end{syntax}
+Replaces all occurrences of \meta{old tokens} in the
+\meta{tl var} with \meta{new tokens}. \meta{Old tokens}
+cannot contain \verb|{|, \verb|}| or \verb|#|
+(more precisely, explicit character tokens with category code $1$
+(begin-group) or $2$ (end-group), and tokens with category code $6$).
+As this function
+operates from left to right, the pattern \meta{old tokens}
+may remain after the replacement (see \cs{TlRemoveAll}
+for an example).
+\end{function}
+
+\begin{function}{\TlRemoveOnce}
+\begin{syntax}
+\cs{TlRemoveOnce} \meta{tl var} \Arg{tokens}
+\end{syntax}
+Removes the first (leftmost) occurrence of \meta{tokens} from the
+\meta{tl var}. \meta{Tokens} cannot contain \verb|{|, \verb|}| or \verb|#|
+(more precisely, explicit character tokens with category code $1$
+(begin-group) or $2$ (end-group), and tokens with category code $6$).
+\end{function}
+
+\begin{function}{\TlRemoveAll}
+\begin{syntax}
+\cs{TlRemoveAll} \meta{tl var} \Arg{tokens}
+\end{syntax}
+Removes all occurrences of \meta{tokens} from the
+\meta{tl var}. \meta{Tokens} cannot contain \verb|{|, \verb|}| or \verb|#|
+(more precisely, explicit character tokens with category code $1$
+(begin-group) or $2$ (end-group), and tokens with category code $6$).
+As this function
+operates from left to right, the pattern \meta{tokens}
+may remain after the removal, for instance,
+\begin{demohigh}
+\TlSet \lTmpaTl {abbccd}
+\TlRemoveAll \lTmpaTl {bc}
+\TlUse \lTmpaTl
\end{demohigh}
\end{function}
+\begin{function}{\TlTrimSpaces}
+\begin{syntax}
+\cs{TlTrimSpaces} \Arg{token list}
+\end{syntax}
+Removes any leading and trailing explicit space characters
+(explicit tokens with character code $32$ and category code $10$)
+from the \meta{token list} and returns the result.
+%\begin{texnote}
+%The result is returned within \tn{unexpanded}, which means that the token
+%list does not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\TlVarTrimSpaces}
+\begin{syntax}
+\cs{TlVarTrimSpaces} \meta{tl var}
+\end{syntax}
+Sets the \meta{tl var} to contain the result of removing any leading
+and trailing explicit space characters (explicit tokens with
+character code $32$ and category code $10$) from its contents.
+\end{function}
+
+\section{Working with the Content of Token Lists}
+
+\begin{function}{\TlCount}
+\begin{syntax}
+\cs{TlCount} \Arg{tokens}
+\end{syntax}
+Counts the number of \meta{items} in \meta{tokens} and returns this information.
+Unbraced tokens count as one element as do each token group (\verb|{|$\cdots$\verb|}|).
+This process ignores any unprotected spaces within \meta{tokens}. %See also \cs{TlVarCount}.
+%This function requires three expansions, giving an \meta{integer denotation}.
+\end{function}
+
+\begin{function}{\TlVarCount}
+\begin{syntax}
+\cs{TlVarCount} \meta{tl var}
+\end{syntax}
+Counts the number of \meta{items} in the \meta{tl var} and returns this information.
+Unbraced tokens count as one element as do each token group (\verb|{|$\cdots$\verb|}|).
+This process ignores any unprotected spaces within the \meta{tl var}. %See also \cs{TlCount}.
+%This function requires three expansions, giving an \meta{integer denotation}.
+\end{function}
+
+\begin{function}{\TlHead}
+\begin{syntax}
+\cs{TlHead} \Arg{token list}
+\end{syntax}
+Returns the first \meta{item} in the \meta{token list},
+discarding the rest of the \meta{token list}.
+All leading explicit space characters
+(explicit tokens with character code $32$ and category code $10$)
+are discarded; for example
+\begin{demohigh}
+\fbox {1\TlHead{ abc }2}
+\fbox {1\TlHead{ abc }2}
+\end{demohigh}
+If the \enquote{head} is a brace group, rather than a single token,
+the braces are removed, and so
+\begin{codehigh}
+\TlHead { { ab} c }
+\end{codehigh}
+yields \verb*| ab|.
+A blank \meta{token list} (see \cs{TlIfBlank}) results in
+\cs{TlHead} returning nothing.
+%\begin{texnote}
+%The result is returned within \cs{exp_not:n}, which means that the token
+%list does not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\TlVarHead}
+\begin{syntax}
+\cs{TlVarHead} \meta{tl var}
+\end{syntax}
+Returns the first \meta{item} in the \meta{tl var},
+discarding the rest of the \meta{tl var}.
+All leading explicit space characters
+(explicit tokens with character code $32$ and category code $10$)
+are discarded.
+\end{function}
+
+\begin{function}{\TlTail}
+\begin{syntax}
+\cs{TlTail} \Arg{token list}
+\end{syntax}
+Discards all leading explicit space characters
+(explicit tokens with character code $32$ and category code $10$)
+and the first \meta{item} in the \meta{token list}, and returns the
+remaining tokens. Thus for example
+\begin{codehigh}
+\TlTail { a {bc} d }
+\end{codehigh}
+and
+\begin{codehigh}
+\TlTail { a {bc} d }
+\end{codehigh}
+both return \verb*| {bc} d |. A blank \meta{token list} (see \cs{TlIfBlank})
+results in \cs{TlTail} returning nothing.
+%\begin{texnote}
+%The result is returned within \cs{exp_not:n}, which means that the
+%token list does not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\TlVarTail}
+\begin{syntax}
+\cs{TlVarTail} \meta{tl var}
+\end{syntax}
+Discards all leading explicit space characters
+(explicit tokens with character code $32$ and category code $10$)
+and the first \meta{item} in the \meta{tl var}, and returns the
+remaining tokens.
+\end{function}
+
+\begin{function}{\TlItem,\TlVarItem}
+\begin{syntax}
+\cs{TlItem} \Arg{token list} \Arg{integer expression}
+\cs{TlVarItem} \meta{tl var} \Arg{integer expression}
+\end{syntax}
+Indexing items in the \meta{token list} from $1$ on the left, this
+function evaluates the \meta{integer expression} and returns the
+appropriate item from the \meta{token list}.
+If the \meta{integer expression} is negative, indexing occurs from
+the right of the token list, starting at $-1$ for the right-most item.
+If the index is out of bounds, then the function returns nothing.
+%\begin{texnote}
+%The result is returned within the \tn{unexpanded}
+%primitive (\cs{exp_not:n}), which means that the \meta{item}
+%does not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\TlRandItem,\TlVarRandItem}
+\begin{syntax}
+\cs{TlRandItem} \Arg{token list}
+\cs{TlVarRandItem} \meta{tl var}
+\end{syntax}
+Selects and returns a pseudo-random item of the \meta{token list}.
+If the \meta{token list} is blank, the result is empty.
+%This is not available in older versions of \XeTeX{}.
+%\begin{texnote}
+%The result is returned within the \tn{unexpanded}
+%primitive (\cs{exp_not:n}), which means that the \meta{item}
+%does not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\section{Mapping over Token Lists}
+
+All mappings are done at the current group level, \emph{i.e.} any
+local assignments made by the \meta{function} or \meta{code} discussed
+below remain in effect after the loop.
+
+%\begin{function}{\TlMapFunction}
+%\begin{syntax}
+%\cs{TlMapFunction} \Arg{token list} \meta{function}
+%\end{syntax}
+%Applies \meta{function} to every \meta{item} in the \meta{token list},
+%The \meta{function} receives one argument for each iteration.
+%This may be a number of tokens if the \meta{item} was stored within
+%braces. Hence the \meta{function} should anticipate receiving
+%\texttt{n}-type arguments.
+%\end{function}
+%
+%\begin{function}{\TlVarMapFunction}
+%\begin{syntax}
+%\cs{TlVarMapFunction} \meta{tl var} \meta{function}
+%\end{syntax}
+%Applies \meta{function} to every \meta{item} in the \meta{tl var}.
+%The \meta{function} receives one argument for each iteration.
+%This may be a number of tokens if the \meta{item} was stored within
+%braces. Hence the \meta{function} should anticipate receiving
+%\texttt{n}-type arguments.
+%\end{function}
+
+\begin{function}{\TlMapInline}
+\begin{syntax}
+\cs{TlMapInline} \Arg{token list} \Arg{inline function}
+\end{syntax}
+Applies the \meta{inline function} to every \meta{item} stored within the
+\meta{token list}. The \meta{inline function} should consist of code which
+receives the \meta{item} as \verb|#1|.
+\end{function}
+
+\begin{function}{\TlVarMapInline}
+\begin{syntax}
+\cs{TlVarMapInline} \meta{tl var} \Arg{inline function}
+\end{syntax}
+Applies the \meta{inline function} to every \meta{item} stored within the
+\meta{tl var}. The \meta{inline function} should consist of code which
+receives the \meta{item} as \verb|#1|.
+\end{function}
+
+%\begin{function}{\TlMapTokens,\TlVarMapTokens}
+%\begin{syntax}
+%\cs{TlMapTokens} \Arg{tokens} \Arg{code}
+%\cs{TlVarMapTokens} \meta{tl var} \Arg{code}
+%\end{syntax}
+%Analogue of \cs{tl_map_function:NN} which maps several tokens
+%instead of a single function. The \meta{code} receives each \meta{item} in
+%the \meta{tl var} or in \meta{tokens} as a trailing brace group. For
+%instance,
+%\begin{verbatim}
+%\tl_map_tokens:Nn \l_my_tl { \prg_replicate:nn { 2 } }
+%\end{verbatim}
+%expands to twice each \meta{item} in the \meta{tl var}: for each \meta{item} in
+%\cs{l_my_tl} the function \cs{prg_replicate:nn} receives |2| and
+%\meta{item} as its two arguments. The function
+%\cs{tl_map_inline:Nn} is typically faster but is not expandable.
+%\end{function}
+
+\begin{function}{\TlMapVariable}
+\begin{syntax}
+\cs{TlMapVariable} \Arg{token list} \meta{variable} \Arg{code}
+\end{syntax}
+Stores each \meta{item} of the \meta{token list} in turn in the
+(token list) \meta{variable} and applies the \meta{code}. The
+\meta{code} will usually make use of the \meta{variable}, but this
+is not enforced. The assignments to the \meta{variable} are local.
+Its value after the loop is the last \meta{item} in the
+\meta{tl var}, or its original value if the \meta{tl var} is blank.
+\end{function}
+
+\begin{function}{\TlVarMapVariable}
+\begin{syntax}
+\cs{TlVarMapVariable} \meta{tl var} \meta{variable} \Arg{code}
+\end{syntax}
+Stores each \meta{item} of the \meta{tl var} in turn in the (token
+list) \meta{variable} and applies the \meta{code}. The \meta{code}
+will usually make use of the \meta{variable}, but this is not
+enforced. The assignments to the \meta{variable} are local. Its
+value after the loop is the last \meta{item} in the \meta{tl var},
+or its original value if the \meta{tl var} is blank.
+\end{function}
+
+%\begin{function}{\TlMapBreak}
+%\begin{syntax}
+%\cs{TlMapBreak}
+%\end{syntax}
+%Used to terminate a tl map function before all
+%entries in the \meta{token list variable} have been processed. This
+%normally takes place within a conditional statement, for example
+%\begin{verbatim}
+%\tl_map_inline:Nn \l_my_tl
+%{
+%\str_if_eq:nnT { #1 } { bingo } { \tl_map_break: }
+%Do something useful
+%}
+%\end{verbatim}
+%See also \cs{tl_map_break:n}.
+%Use outside of a tl map scenario leads to low
+%level \TeX{} errors.
+%\begin{texnote}
+%When the mapping is broken, additional tokens may be inserted
+%before the \meta{tokens} are
+%inserted into the input stream.
+%This depends on the design of the mapping function.
+%\end{texnote}
+%\end{function}
+%
+%\begin{function}{\TlMapBreakDo}
+%\begin{syntax}
+%\cs{TlMapBreakDo} \Arg{code}
+%\end{syntax}
+%Used to terminate a tl map function before all
+%entries in the \meta{token list variable} have been processed, inserting
+%the \meta{code} after the mapping has ended. This
+%normally takes place within a conditional statement, for example
+%\begin{verbatim}
+%\tl_map_inline:Nn \l_my_tl
+%{
+%\str_if_eq:nnT { #1 } { bingo }
+%{ \tl_map_break:n { <code> } }
+%Do something useful
+%}
+%\end{verbatim}
+%Use outside of a tl map scenario leads to low
+%level \TeX{} errors.
+%\begin{texnote}
+%When the mapping is broken, additional tokens may be inserted
+%before the \meta{code} is
+%inserted into the input stream.
+%This depends on the design of the mapping function.
+%\end{texnote}
+%\end{function}
+
+\section{Token List Conditionals}
+
+\begin{function}{\TlIfExist,\TlIfExistTF}
+\begin{syntax}
+\cs{TlIfExist} \meta{tl var}
+\cs{TlIfExistTF} \meta{tl var} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests whether the \meta{tl var} is currently defined. This does not
+check that the \meta{tl var} really is a token list variable.
+\end{function}
+
\begin{function}{\TlIfEmpty,\TlIfEmptyTF}
\begin{syntax}
-\cs{TlIfEmpty} \meta{tl~var}
-\cs{TlIfEmptyTF} \meta{tl~var} \Arg{true code} \Arg{false code}
+\cs{TlIfEmpty} \Arg{token list}
+\cs{TlIfEmptyTF} \Arg{token list} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the \meta{token list} is entirely empty
+(\emph{i.e.}~contains no tokens at all). For example
+\begin{demohigh}
+\TlIfEmptyTF {abc} {\Result{Empty}} {\Result{NonEmpty}}
+\TlIfEmptyTF {} {\Result{Empty}} {\Result{NonEmpty}}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\TlVarIfEmpty,\TlVarIfEmptyTF}
+\begin{syntax}
+\cs{TlVarIfEmpty} \meta{tl~var}
+\cs{TlVarIfEmptyTF} \meta{tl~var} \Arg{true code} \Arg{false code}
\end{syntax}
Tests if the \meta{token list variable} is entirely empty
(\emph{i.e.}~contains no tokens at all). For example
\begin{demohigh}
-\TlSet\lTmpaTl{abc}
-\TlIfEmptyTF\lTmpaTl{\Result{Empty}}{\Result{NonEmpty}}
-\TlClear\lTmpaTl
-\TlIfEmptyTF\lTmpaTl{\Result{Empty}}{\Result{NonEmpty}}
+\TlSet \lTmpaTl {abc}
+\TlVarIfEmptyTF \lTmpaTl {\Result{Empty}} {\Result{NonEmpty}}
+\TlClear \lTmpaTl
+\TlVarIfEmptyTF \lTmpaTl {\Result{Empty}} {\Result{NonEmpty}}
\end{demohigh}
\end{function}
+\begin{function}{\TlIfBlank}
+\begin{syntax}
+\cs{TlIfBlank} \Arg{token list}
+\cs{TlIfBlankTF} \Arg{token list} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the \meta{token list} consists only of blank spaces
+(\emph{i.e.} contains no item). The test is \texttt{true} if
+\meta{token list} is zero or more explicit space characters
+(explicit tokens with character code $32$ and category code $10$),
+and is \texttt{false} otherwise.
+\end{function}
+
\begin{function}{\TlIfEq,\TlIfEqTF}
\begin{syntax}
-\cs{TlIfEq} \meta{tl~var_1} \meta{tl~var_2}
-\cs{TlIfEqTF} \meta{tl~var_1} \meta{tl~var_2} \Arg{true code} \Arg{false code}
+\cs{TlIfEq} \Arg{token list_1} \Arg{token list_2}
+\cs{TlIfEqTF} \Arg{token list_1} \Arg{token list_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if \meta{token list_1} and \meta{token list_2} contain the
+same list of tokens, both in respect of character codes and category
+codes. See \cs{StrIfEq} if category codes are not important.
+For example
+\begin{demohigh}
+\TlIfEqTF {abc} {abc} {\Result{Yes}} {\Result{No}}
+\TlIfEqTF {abc} {xyz} {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+%\begin{demohigh}
+%\TlSet\lTmpaTl{abc}
+%\TlSet\lTmpbTl{abc}
+%\TlSet\lTmpcTl{xyz}
+%\TlIfEqTF{\TlUse\lTmpaTl}{\TlUse\lTmpbTl}{\Result{Yes}}{\Result{No}}
+%\TlIfEqTF{\TlUse\lTmpaTl}{\TlUse\lTmpcTl}{\Result{Yes}}{\Result{No}}
+%\end{demohigh}
+\end{function}
+
+\begin{function}{\TlVarIfEq,\TlVarIfEqTF}
+\begin{syntax}
+\cs{TlVarIfEq} \meta{tl var_1} \meta{tl var_2}
+\cs{TlVarIfEqTF} \meta{tl var_1} \meta{tl var_2} \Arg{true code} \Arg{false code}
\end{syntax}
Compares the content of two \meta{token list variables} and
is logically \texttt{true} if the two contain the same list of
tokens (\emph{i.e.}~identical in both the list of characters they
contain and the category codes of those characters). For example
\begin{demohigh}
-\TlSet\lTmpaTl{abc}
-\TlSet\lTmpbTl{abc}
-\TlSet\lTmpcTl{xyz}
-\TlIfEqTF\lTmpaTl\lTmpbTl{\Result{Yes}}{\Result{No}}
-\TlIfEqTF\lTmpaTl\lTmpcTl{\Result{Yes}}{\Result{No}}
+\TlSet \lTmpaTl {abc}
+\TlSet \lTmpbTl {abc}
+\TlSet \lTmpcTl {xyz}
+\TlVarIfEqTF \lTmpaTl \lTmpbTl {\Result{Yes}} {\Result{No}}
+\TlVarIfEqTF \lTmpaTl \lTmpcTl {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+See also \cs{StrVarIfEq} for a comparison that ignores category codes.
+\end{function}
+
+\begin{function}{\TlIfIn,\TlIfInTF}
+\begin{syntax}
+\cs{TlIfIn} \Arg{token list_1} \Arg{token list_2}
+\cs{TlIfInTF} \Arg{token list_1} \Arg{token list_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if \meta{token list_2} is found inside \meta{token list_1}.
+The \meta{token list_2} cannot contain the tokens \verb|{|, \verb|}| or \verb|#|
+(more precisely, explicit character tokens with category code $1$
+(begin-group) or $2$ (end-group), and tokens with category code $6$).
+The search does \emph{not} enter brace (category code $1$/$2$) groups.
+\end{function}
+
+\begin{function}{\TlVarIfIn,\TlVarIfInTF}
+\begin{syntax}
+\cs{TlVarIfIn} \meta{tl var} \Arg{token list}
+\cs{TlVarIfInTF} \meta{tl var} \Arg{token list} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the \meta{token list} is found in the content of the
+\meta{tl var}. The \meta{token list} cannot contain
+the tokens \verb|{|, \verb|}| or \verb|#|
+(more precisely, explicit character tokens with category code $1$
+(begin-group) or $2$ (end-group), and tokens with category code $6$).
+\end{function}
+
+\begin{function}{\TlIfSingle,\TlIfSingleTF}
+\begin{syntax}
+\cs{TlIfSingle} \Arg{token list}
+\cs{TlIfSingleTF} \Arg{token list} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the \meta{token list} has exactly one \meta{item}, \emph{i.e.} is
+a single normal token (neither an explicit space character nor a
+begin-group character) or a single brace group, surrounded by
+optional spaces on both sides. In other words, such a token list has
+token count $1$ according to \cs{TlCount}.
+\end{function}
+
+\begin{function}{\TlVarIfSingle,\TlVarIfSingleTF}
+\begin{syntax}
+\cs{TlVarIfSingle} \meta{tl var}
+\cs{TlVarIfSingleTF} \meta{tl var} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the content of the \meta{tl var} consists of a single \meta{item},
+\emph{i.e.} is a single normal token (neither an explicit space
+character nor a begin-group character) or a single brace group,
+surrounded by optional spaces on both sides. In other words, such a
+token list has token count $1$ according to \cs{TlVarCount}.
+\end{function}
+
+\section{Token List Case Functions}
+
+\begin{function}{\TlVarCase}
+\begin{syntax}
+\cs{TlVarCase} \meta{test token list variable}
+~ ~ \verb"{"
+~ ~ ~ ~ \meta{token list variable case_1} \Arg{code case_1}
+~ ~ ~ ~ \meta{token list variable case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \meta{token list variable case_n} \Arg{code case_n}
+~ ~ \verb"}"
+\end{syntax}
+This function compares the \meta{test token list variable} in turn
+with each of the \meta{token list variable cases}. If the two
+are equal (as described for \cs{TlVarIfEq})
+then the associated \meta{code} is left in the input
+stream and other cases are discarded. The function
+does nothing if there is no match.
+\end{function}
+
+\begin{function}{\TlVarCaseT}
+\begin{syntax}
+\cs{TlVarCaseT} \meta{test token list variable}
+~ ~ \verb"{"
+~ ~ ~ ~ \meta{token list variable case_1} \Arg{code case_1}
+~ ~ ~ ~ \meta{token list variable case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \meta{token list variable case_n} \Arg{code case_n}
+~ ~ \verb"}"
+~ ~ \Arg{true code}
+\end{syntax}
+This function compares the \meta{test token list variable} in turn
+with each of the \meta{token list variable cases}. If the two
+are equal (as described for \cs{TlVarIfEq})
+then the associated \meta{code} is left in the input
+stream and other cases are discarded. If any of the
+cases are matched, the \meta{true code} is also inserted into the
+input stream (after the code for the appropriate case).
+\end{function}
+
+\begin{function}{\TlVarCaseF}
+\begin{syntax}
+\cs{TlVarCaseF} \meta{test token list variable}
+~ ~ \verb"{"
+~ ~ ~ ~ \meta{token list variable case_1} \Arg{code case_1}
+~ ~ ~ ~ \meta{token list variable case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \meta{token list variable case_n} \Arg{code case_n}
+~ ~ \verb"}"
+~ ~ \Arg{false code}
+\end{syntax}
+This function compares the \meta{test token list variable} in turn
+with each of the \meta{token list variable cases}. If the two
+are equal (as described for \cs{TlVarIfEq})
+then the associated \meta{code} is left in the input
+stream and other cases are discarded. If none
+match then the \meta{false code} is inserted into the input stream
+ (after the code for the appropriate case).
+\end{function}
+
+\begin{function}{\TlVarCaseTF}
+\begin{syntax}
+\cs{TlVarCaseTF} \meta{test token list variable}
+~ ~ \verb"{"
+~ ~ ~ ~ \meta{token list variable case_1} \Arg{code case_1}
+~ ~ ~ ~ \meta{token list variable case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \meta{token list variable case_n} \Arg{code case_n}
+~ ~ \verb"}"
+~ ~ \Arg{true code}
+~ ~ \Arg{false code}
+\end{syntax}
+This function compares the \meta{test token list variable} in turn
+with each of the \meta{token list variable cases}. If the two
+are equal (as described for \cs{TlVarIfEq})
+then the associated \meta{code} is left in the input
+stream and other cases are discarded. If any of the
+cases are matched, the \meta{true code} is also inserted into the
+input stream (after the code for the appropriate case), while if none
+match then the \meta{false code} is inserted. The function
+\cs{TlVarCase}, which does nothing if there is no match, is also
+available.
+\end{function}
+
+\chapter{Strings (\texttt{Str})}
+
+\section{Constant and Scratch Strings}
+
+\begin{variable}{\cAmpersandStr,\cAtsignStr,\cBackslashStr,\cLeftBraceStr,\cRightBraceStr,
+\cCircumflexStr,\cColonStr,\cDollarStr,\cHashStr,\cPercentStr,\cTildeStr,\cUnderscoreStr,\cZeroStr}
+Constant strings, containing a single character token, with category code $12$.
+\end{variable}
+
+\begin{variable}{\lTmpaStr,\lTmpbStr,\lTmpcStr,\lTmpiStr,\lTmpjStr,\lTmpkStr}
+Scratch strings for local assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\begin{variable}{\gTmpaStr,\gTmpbStr,\gTmpcStr,\gTmpiStr,\gTmpjStr,\gTmpkStr}
+Scratch strings for global assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\section{Creating and Using Strings}
+
+\begin{function}{\StrNew}
+\begin{syntax}
+\cs{StrNew} \meta{str var}
+\end{syntax}
+Creates a new \meta{str var} or raises an error if the name is
+already taken. The declaration is global. The \meta{str var} is
+initially empty.
+\end{function}
+
+\begin{function}{\StrConst}
+\begin{syntax}
+\cs{StrConst} \meta{str var} \Arg{token list}
+\end{syntax}
+Creates a new constant \meta{str var} or raises an error if the name
+is already taken. The value of the \meta{str var} is set
+globally to the \meta{token list}, converted to a string.
+\end{function}
+
+\begin{function}{\StrUse}
+\begin{syntax}
+\cs{StrUse} \meta{str var}
+\end{syntax}
+Recovers the content of a \meta{str var} and returns the value.
+An error is raised if the variable
+does not exist or if it is invalid. Note that it is possible to use
+a \meta{str} directly without an accessor function.
+\end{function}
+
+\section{Viewing Strings}
+
+\begin{function}{\StrLog}
+\begin{syntax}
+\cs{StrLog} \Arg{token list}
+\end{syntax}
+Writes \meta{token list} in the log file.
+\end{function}
+
+\begin{function}{\StrVarLog}
+\begin{syntax}
+\cs{StrVarLog} \meta{str var}
+\end{syntax}
+Writes the content of the \meta{str var} in the log file.
+For example
+\begin{codehigh}
+\StrSet \lTmpiStr {1234\abcd5678}
+\StrVarLog \lTmpiStr
+\end{codehigh}
+\end{function}
+
+\begin{function}{\StrShow}
+\begin{syntax}
+\cs{StrShow} \Arg{token list}
+\end{syntax}
+Displays \meta{token list} on the terminal.
+\end{function}
+
+\begin{function}{\StrVarShow}
+\begin{syntax}
+\cs{StrVarShow} \meta{str var}
+\end{syntax}
+Displays the content of the \meta{str var} on the terminal.
+\end{function}
+
+\section{Setting String Variables}
+
+\begin{function}{\StrSet}
+\begin{syntax}
+\cs{StrSet} \meta{str var} \Arg{token list}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string}, and stores the
+result in \meta{str var}. For example
+\begin{demohigh}
+\StrSet \lTmpiStr {\IntMathMult{4}{5}}
+\StrUse \lTmpiStr
+\end{demohigh}
+\end{function}
+
+\begin{function}{\StrSetEq}
+\begin{syntax}
+\cs{StrSetEq} \meta{str var_1} \meta{str var_2}
+\end{syntax}
+Sets the content of \meta{str var_1} equal to that of
+\meta{str var_2}.
+\end{function}
+
+\begin{function}{\StrClear}
+\begin{syntax}
+\cs{StrClear} \meta{str var}
+\end{syntax}
+Clears the content of the \meta{str var}. For example
+\begin{demohigh}
+\StrSet \lTmpjStr {One}
+\StrClear \lTmpjStr
+\StrSet \lTmpjStr {Two}
+\StrUse \lTmpjStr
+\end{demohigh}
+\end{function}
+
+\begin{function}{\StrClearNew}
+\begin{syntax}
+\cs{StrClearNew} \meta{str var}
+\end{syntax}
+Ensures that the \meta{str var} exists globally by applying
+\cs{StrNew} if necessary, then applies \cs{StrClear} to leave
+the \meta{str var} empty.
+\end{function}
+
+\begin{function}{\StrConcat}
+\begin{syntax}
+\cs{StrConcat} \meta{str var_1} \meta{str var_2} \meta{str var_3}
+\end{syntax}
+Concatenates the content of \meta{str var_2} and \meta{str var_3}
+together and saves the result in \meta{str var_1}. The \meta{str var_2}
+is placed at the left side of the new string variable.
+The \meta{str var_2} and \meta{str var_3} must indeed be strings, as
+this function does not convert their contents to a string.
+\end{function}
+
+\begin{function}{\StrPutLeft}
+\begin{syntax}
+\cs{StrPutLeft} \meta{str var} \Arg{token list}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string}, and prepends the
+result to \meta{str var}. The current contents of the \meta{str
+var} are not automatically converted to a string. For example
+\begin{demohigh}
+\StrSet \lTmpkStr {Functional}
+\StrPutLeft \lTmpkStr {Hello}
+\StrUse \lTmpkStr
+\end{demohigh}
+\end{function}
+
+\begin{function}{\StrPutRight}
+\begin{syntax}
+\cs{StrPutRight} \meta{str var} \Arg{token list}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string}, and appends the
+result to \meta{str var}. The current contents of the \meta{str
+var} are not automatically converted to a string. For example
+\begin{demohigh}
+\StrSet \lTmpkStr {Functional}
+\StrPutRight \lTmpkStr {World}
+\StrUse \lTmpkStr
+\end{demohigh}
+\end{function}
+
+\section{Modifying String Variables}
+
+\begin{function}{\StrReplaceOnce}
+\begin{syntax}
+\cs{StrReplaceOnce} \meta{str var} \Arg{old} \Arg{new}
+\end{syntax}
+Converts the \meta{old} and \meta{new} token lists to strings, then
+replaces the first (leftmost) occurrence of \meta{old string} in the
+\meta{str var} with \meta{new string}.
+\end{function}
+
+\begin{function}{\StrReplaceAll}
+\begin{syntax}
+\cs{StrReplaceAll} \meta{str var} \Arg{old} \Arg{new}
+\end{syntax}
+Converts the \meta{old} and \meta{new} token lists to strings, then
+replaces all occurrences of \meta{old string} in the
+\meta{str var} with \meta{new string}.
+As this function
+operates from left to right, the pattern \meta{old string}
+may remain after the replacement.
+\end{function}
+
+\begin{function}{\StrRemoveOnce}
+\begin{syntax}
+\cs{StrRemoveOnce} \meta{str var} \Arg{token list}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string} then
+removes the first (leftmost) occurrence of \meta{string} from the
+\meta{str var}.
+\end{function}
+
+\begin{function}{\StrRemoveAll}
+\begin{syntax}
+\cs{StrRemoveAll} \meta{str var} \Arg{token list}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string} then
+removes all occurrences of \meta{string} from the \meta{str var}.
+As this function operates from left to right,
+the pattern \meta{string} may remain after the removal, for instance,
+\begin{demohigh}
+\StrSet \lTmpaStr {abbccd}
+\StrRemoveAll \lTmpaStr {bc}
+\TlUse \lTmpaStr
+\end{demohigh}
+\end{function}
+
+\section{Working with the Content of Strings}
+
+\begin{function}{\StrCount}
+\begin{syntax}
+\cs{StrCount} \Arg{token list}
+\end{syntax}
+Returns the number of characters in the string representation of \meta{token list},
+as an integer denotation. All characters including spaces are counted.
+\par
+Due to naming conflict, you need to use \cs{StrSize} instead of \cs{StrCount}
+if you want to use \verb!functional! package together with \verb!xstring! package.
+\end{function}
+
+\begin{function}{\StVarCount}
+\begin{syntax}
+\cs{StrVarCount} \meta{tl var}
+\end{syntax}
+Returns the number of characters in the string representation of the \meta{tl var},
+as an integer denotation. All characters including spaces are counted.
+\end{function}
+
+\begin{function}{\StrHead}
+\begin{syntax}
+\cs{StrHead} \Arg{token list}
+\end{syntax}
+Converts the \meta{token list} into a \meta{string}.
+The first character in the \meta{string} is then returned,
+with category code \enquote{other}. If the first character is a space,
+it returns a space token with category code $10$ (blank space).
+If the \meta{string} is empty, then nothing is returned.
+\end{function}
+
+\begin{function}{\StrVarHead}
+\begin{syntax}
+\cs{StrVarHead} \meta{tl var}
+\end{syntax}
+Converts the \meta{tl var} into a \meta{string}.
+The first character in the \meta{string} is then returned,
+with category code \enquote{other}. If the first character is a space,
+it returns a space token with category code $10$ (blank space).
+If the \meta{string} is empty, then nothing is returned.
+\end{function}
+
+\begin{function}{\StrTail}
+\begin{syntax}
+\cs{StrTail} \Arg{token list}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string}, removes the first
+character, and returns the remaining characters (if any)
+with category codes $12$ and $10$ (for spaces).
+If the first character is a space, it only trims that space.
+If the \meta{token list} is empty,
+then nothing is left on the input stream.
+\end{function}
+
+\begin{function}{\StrVarTail}
+\begin{syntax}
+\cs{StrVarTail} \meta{tl var}
+\end{syntax}
+Converts the \meta{tl var} to a \meta{string}, removes the first
+character, and returns the remaining characters (if any)
+with category codes $12$ and $10$ (for spaces).
+If the first character is a space, it only trims that space.
+If the \meta{token list} is empty,
+then nothing is left on the input stream.
+\end{function}
+
+\begin{function}{\StrItem}
+\begin{syntax}
+\cs{StrItem} \Arg{token list} \Arg{integer expression}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string},
+and returns the character in position \meta{integer expression} of
+the \meta{string}, starting at $1$ for the first (left-most)
+character. All characters including spaces are taken into account.
+If the \meta{integer expression} is negative,
+characters are counted from the end of the \meta{string}. Hence,
+$-1$ is the right-most character, \emph{etc.}
+\end{function}
+
+\begin{function}{\StrVarItem}
+\begin{syntax}
+\cs{StrVarItem} \meta{tl var} \Arg{integer expression}
+\end{syntax}
+Converts the \meta{tl var} to a \meta{string},
+and returns the character in position \meta{integer expression} of
+the \meta{string}, starting at $1$ for the first (left-most)
+character. All characters including spaces are taken into account.
+If the \meta{integer expression} is negative,
+characters are counted from the end of the \meta{string}. Hence,
+$-1$ is the right-most character, \emph{etc.}
+\end{function}
+
+\section{Mapping over Strings}
+
+All mappings are done at the current group level, \emph{i.e.} any
+local assignments made by the \meta{function} or \meta{code} discussed
+below remain in effect after the loop.
+
+%\begin{function}{\StrMapFunction,\StrVarMapFunction}
+%\begin{syntax}
+%\cs{StrMapFunction} \Arg{token list} \meta{function}
+%\cs{StrVarMapFunction} \meta{str var} \meta{function}
+%\end{syntax}
+%Converts the \meta{token list} to a \meta{string} then
+%applies \meta{function} to every \meta{character} in the
+%\meta{string} including spaces.
+%\end{function}
+
+\begin{function}{\StrMapInline,\StrVarMapInline}
+\begin{syntax}
+\cs{StrMapInline} \Arg{token list} \Arg{inline function}
+\cs{StrVarMapInline} \meta{str var} \Arg{inline function}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string} then
+applies the \meta{inline function} to every \meta{character} in the
+\meta{str var} including spaces.
+The \meta{inline function} should consist of code which
+receives the \meta{character} as \verb|#1|.
+\end{function}
+
+%\begin{function}{\StrMapTokens, \StrVarMapTokens}
+%\begin{syntax}
+%\cs{StrMapTokens} \Arg{token list} \Arg{code}
+%\cs{StrVarMapTokens} \meta{str var} \Arg{code}
+%\end{syntax}
+%Converts the \meta{token list} to a \meta{string} then applies
+%\meta{code} to every \meta{character} in the \meta{string} including spaces.
+%The \meta{code} receives each character as a trailing brace group.
+%This is equivalent to \cs{StrMapFunction} if the
+%\meta{code} consists of a single function.
+%\end{function}
+
+\begin{function}{\StrMapVariable,\StrMapVariable}
+\begin{syntax}
+\cs{StrMapVariable} \Arg{token list} \meta{variable} \Arg{code}
+\cs{StrVarMapVariable} \meta{str var} \meta{variable} \Arg{code}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string} then stores each
+\meta{character} in the \meta{string} (including spaces) in turn in
+the (string or token list) \meta{variable} and applies the
+\meta{code}. The \meta{code} will usually make use of the
+\meta{variable}, but this is not enforced. The assignments to the
+\meta{variable} are local. Its value after the loop is the last
+\meta{character} in the \meta{string}, or its original value if the
+\meta{string} is empty.
+\end{function}
+
+%\begin{function}{\StrMapBreak}
+%\begin{syntax}
+%\cs{StrMapBreak}
+%\end{syntax}
+%Used to terminate a string map function before all
+%characters in the \meta{string} have been processed. This
+%normally takes place within a conditional statement, for example
+%\begin{verbatim}
+%\str_map_inline:Nn \l_my_str
+%{
+%\str_if_eq:nnT { #1 } { bingo } { \str_map_break: }
+%Do something useful
+%}
+%\end{verbatim}
+%See also \cs{StrMapBreakDo}.
+%Use outside of a string map scenario leads to low
+%level \TeX{} errors.
+%\begin{texnote}
+%When the mapping is broken, additional tokens may be inserted
+%before continuing with the
+%code that follows the loop.
+%This depends on the design of the mapping function.
+%\end{texnote}
+%\end{function}
+%
+%\begin{function}{\StrMapBreakDo}
+%\begin{syntax}
+%\cs{StrMapBreakDo} \Arg{code}
+%\end{syntax}
+%Used to terminate a string map function before all
+%characters in the \meta{string} have been processed, inserting
+%the \meta{code} after the mapping has ended. This
+%normally takes place within a conditional statement, for example
+%\begin{verbatim}
+%\str_map_inline:Nn \l_my_str
+%{
+%\str_if_eq:nnT { #1 } { bingo }
+%{ \str_map_break:n { <code> } }
+%Do something useful
+%}
+%\end{verbatim}
+%Use outside of a string map scenario leads to low
+%level \TeX{} errors.
+%\begin{texnote}
+%When the mapping is broken, additional tokens may be inserted
+%before the \meta{code} is
+%inserted into the input stream.
+%This depends on the design of the mapping function.
+%\end{texnote}
+%\end{function}
+
+\section{String Conditionals}
+
+\begin{function}{\StrIfExist,\StrIfExistTF}
+\begin{syntax}
+\cs{StrIfExist} \meta{str var}
+\cs{StrIfExistTF} \meta{str var} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests whether the \meta{str var} is currently defined. This does not
+check that the \meta{str var} really is a string.
+\end{function}
+
+\begin{function}{\StrVarIfEmpty,\StrVarIfEmptyTF}
+\begin{syntax}
+\cs{StrVarIfEmpty} \meta{str var}
+\cs{StrVarIfEmptyTF} \meta{str var} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the \meta{string variable} is entirely empty
+(\emph{i.e.} contains no characters at all). For example
+\begin{demohigh}
+\StrSet \lTmpaStr {abc}
+\StrVarIfEmptyTF \lTmpaStr {\Result{Empty}} {\Result{NonEmpty}}
+\StrClear \lTmpaStr
+\StrVarIfEmptyTF \lTmpaStr {\Result{Empty}} {\Result{NonEmpty}}
\end{demohigh}
-%See also \cs{StrIfEqTF} for a comparison that ignores category codes.
\end{function}
-\chapter{Integers (\texttt{l3int})}
+\begin{function}{\StrIfEq,\StrIfEqTF}
+\begin{syntax}
+\cs{StrIfEq} \Arg{tl_1} \Arg{tl_2}
+\cs{StrIfEqTF} \Arg{tl_1} \Arg{tl_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Compares the two \meta{token lists} on a character by character
+basis (namely after converting them to strings),
+and is \texttt{true} if the two \meta{strings} contain the same
+characters in the same order.
+%Thus for example
+%\begin{codehigh}
+%\StrIfEq{abc}{\TlToStr{abc}}
+%\end{codehigh}
+%is logically \texttt{true}.
+See \cs{TlIfEq} to compare
+tokens (including their category codes) rather than characters.
+For example
+\begin{demohigh}
+\StrIfEqTF {abc} {abc} {\Result{Yes}} {\Result{No}}
+\StrIfEqTF {abc} {xyz} {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+%\begin{demohigh}
+%\StrSet\lTmpaStr{abc}
+%\StrSet\lTmpbStr{abc}
+%\StrSet\lTmpcStr{xyz}
+%\StrIfEqTF{\lTmpaStr}{\lTmpbStr}{\Result{Yes}}{\Result{No}}
+%\StrIfEqTF{\lTmpaStr}{\lTmpcStr}{\Result{Yes}}{\Result{No}}
+%\StrIfEqTF{\StrUse\lTmpaStr}{\StrUse\lTmpbStr}{\Result{Yes}}{\Result{No}}
+%\StrIfEqTF{\StrUse\lTmpaStr}{\StrUse\lTmpcStr}{\Result{Yes}}{\Result{No}}
+%\end{demohigh}
+\end{function}
-\section{Scratch Variables of Integers}
+\begin{function}{\StrVarIfEq,\StrVarIfEqTF}
+\begin{syntax}
+\cs{StrVarIfEq} \meta{str var_1} \meta{str var_2}
+\cs{StrVarIfEqTF} \meta{str var_1} \meta{str var_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Compares the content of two \meta{str variables} and
+is logically \texttt{true} if the two contain the same characters
+in the same order. See \cs{TlVarIfEq} to compare tokens
+(including their category codes) rather than characters.
+\begin{demohigh}
+\StrSet \lTmpaStr {abc}
+\StrSet \lTmpbStr {abc}
+\StrSet \lTmpcStr {xyz}
+\StrVarIfEqTF \lTmpaStr \lTmpbStr {\Result{Yes}} {\Result{No}}
+\StrVarIfEqTF \lTmpaStr \lTmpcStr {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\StrIfIn,\StrIfInTF}
+\begin{syntax}
+\cs{StrIfInTF} \Arg{tl_1} \Arg{tl_2}
+\cs{StrIfInTF} \Arg{tl_1} \Arg{tl_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Converts both \meta{token lists} to \meta{strings} and
+tests whether \meta{string_2} is found inside \meta{string_1}.
+\end{function}
+
+\begin{function}{\StrVarIfIn,\StrVarIfInTF}
+\begin{syntax}
+\cs{StrVarIfInTF} \meta{str var} \Arg{token list}
+\cs{StrVarIfInTF} \meta{str var} \Arg{token list} \Arg{true code} \Arg{false code}
+\end{syntax}
+Converts the \meta{token list} to a \meta{string} and
+tests if that \meta{string} is found in the content of the
+\meta{str var}.
+\end{function}
+
+\begin{function}{\StrCompare,\StrCompareTF}
+\begin{syntax}
+\cs{StrCompare} \Arg{tl_1} \meta{relation} \Arg{tl_2}
+\cs{StrCompareTF} \Arg{tl_1} \meta{relation} \Arg{tl_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Compares the two \meta{token lists} on a character by character
+basis (namely after converting them to strings) in a lexicographic
+order according to the character codes of the characters. The
+\meta{relation} can be \verb|<|, \verb|=|, or \verb|>| and the test is
+\texttt{true} under the following conditions:
+\begin{itemize}[nosep]
+\item for \verb|<|, if the first string is earlier than the second in lexicographic order;
+\item for \verb|=|, if the two strings have exactly the same characters;
+\item for \verb|>|, if the first string is later than the second in lexicographic order.
+\end{itemize}
+For example:
+\begin{demohigh}
+\StrCompareTF {ab} < {abc} {\Result{Yes}} {\Result{No}}
+\StrCompareTF {ab} < {aa} {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+%\begin{texnote}
+%This is a wrapper around the \TeX{} primitive
+%\cs{(pdf)strcmp}. It is meant for programming
+%and not for sorting textual contents, as it simply considers
+%character codes and not more elaborate considerations of grapheme
+%clusters, locale, etc.
+%\end{texnote}
+\par
+Due to naming conflict, you need to use \cs{StrIfCompare}/\cs{StrIfCompareTF} as a replacement
+if you want to use \verb!functional! package together with \verb!xstring! package.
+\end{function}
+
+\section{String Case Functions}
+
+\begin{function}{\StrCase}
+\begin{syntax}
+\cs{StrCase} \Arg{test string}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{string case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{string case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \Arg{string case_n} \Arg{code case_n}
+~ ~ \verb|}|
+\end{syntax}
+Compares the \meta{test string} in turn with each
+of the \meta{string cases} (all token lists are converted to strings).
+If the two are equal (as described for
+\cs{StrIfEq}) then the associated \meta{code} is left in the
+input stream and other cases are discarded.
+\end{function}
+
+\begin{function}{\StrCaseT}
+\begin{syntax}
+\cs{StrCaseT} \Arg{test string}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{string case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{string case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \Arg{string case_n} \Arg{code case_n}
+~ ~ \verb|}|
+~ ~ \Arg{true code}
+\end{syntax}
+Compares the \meta{test string} in turn with each
+of the \meta{string cases} (all token lists are converted to strings).
+If the two are equal (as described for
+\cs{StrIfEq}) then the associated \meta{code} is left in the
+input stream and other cases are discarded. If any of the
+cases are matched, the \meta{true code} is also inserted into the
+input stream (after the code for the appropriate case).
+\end{function}
+
+\begin{function}{\StrCaseF}
+\begin{syntax}
+\cs{StrCaseF} \Arg{test string}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{string case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{string case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \Arg{string case_n} \Arg{code case_n}
+~ ~ \verb|}|
+~ ~ \Arg{false code}
+\end{syntax}
+Compares the \meta{test string} in turn with each
+of the \meta{string cases} (all token lists are converted to strings).
+If the two are equal (as described for
+\cs{StrIfEq}) then the associated \meta{code} is left in the
+input stream and other cases are discarded. If none
+match then the \meta{false code} is inserted.
+\end{function}
+
+\begin{function}{\StrCaseTF}
+\begin{syntax}
+\cs{StrCaseTF} \Arg{test string}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{string case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{string case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \Arg{string case_n} \Arg{code case_n}
+~ ~ \verb|}|
+~ ~ \Arg{true code}
+~ ~ \Arg{false code}
+\end{syntax}
+Compares the \meta{test string} in turn with each
+of the \meta{string cases} (all token lists are converted to strings).
+If the two are equal (as described for
+\cs{StrIfEq}) then the associated \meta{code} is left in the
+input stream and other cases are discarded. If any of the
+cases are matched, the \meta{true code} is also inserted into the
+input stream (after the code for the appropriate case), while if none
+match then the \meta{false code} is inserted.
+\end{function}
+
+\chapter{Integers (\texttt{Int})}
+
+\section{Constant and Scratch Integers}
+
+\begin{variable}{\cZeroInt,\cOneInt}
+Integer values used with primitive tests and assignments: their
+self-terminating nature makes these more convenient and faster than
+literal numbers.
+\end{variable}
+
+\begin{variable}{\cMaxInt}
+The maximum value that can be stored as an integer.
+\end{variable}
+
+\begin{variable}{\cMaxRegisterInt}
+Maximum number of registers.
+\end{variable}
+
+\begin{variable}{\cMaxCharInt}
+Maximum character code completely supported by the engine.
+\end{variable}
\begin{variable}{\lTmpaInt,\lTmpbInt,\lTmpcInt,\lTmpiInt,\lTmpjInt,\lTmpkInt}
Scratch integer for local assignment. These are never used by
@@ -781,7 +2320,7 @@ function. However, they may be overwritten by other
code and so should only be used for short-term storage.
\end{variable}
-\section{Public Functions for Integers}
+\section{Integer Expressions}
\begin{function}{\IntEval}
\begin{syntax}
@@ -793,7 +2332,7 @@ explicit sequence of decimal digits not starting with~\texttt{0},
for negative results \texttt{-}~followed by such a sequence, and
\texttt{0}~for zero. For example
\begin{demohigh}
-\IntEval{(1+4)*(2-3)/5}
+\IntEval {(1+4)*(2-3)/5}
\end{demohigh}
\end{function}
@@ -804,7 +2343,7 @@ for negative results \texttt{-}~followed by such a sequence, and
Adds \Arg{integer expression_1} and \Arg{integer expression_2},
and returns the result. For example
\begin{demohigh}
-\IntMathAdd{7}{3}
+\IntMathAdd {7} {3}
\end{demohigh}
\end{function}
@@ -812,10 +2351,10 @@ and returns the result. For example
\begin{syntax}
\cs{IntMathSub} \Arg{integer expression_1} \Arg{integer expression_2}
\end{syntax}
-Subtracts \Arg{integer expression_1} from \Arg{integer expression_2},
+Subtracts \Arg{integer expression_2} from \Arg{integer expression_1},
and returns the result. For example
\begin{demohigh}
-\IntMathSub{7}{3}
+\IntMathSub {7} {3}
\end{demohigh}
\end{function}
@@ -826,7 +2365,7 @@ and returns the result. For example
Multiplies \Arg{integer expression_1} by \Arg{integer expression_2},
and returns the result. For example
\begin{demohigh}
-\IntMathMult{7}{3}
+\IntMathMult {7} {3}
\end{demohigh}
\end{function}
@@ -834,13 +2373,85 @@ and returns the result. For example
\begin{syntax}
\cs{IntMathDiv} \Arg{integer expression_1} \Arg{integer expression_2}
\end{syntax}
-Divides \Arg{integer expression_1} by \Arg{integer expression_2},
-and returns the result. For example
+Evaluates the two \meta{integer expressions} as described earlier,
+then divides the first value by the second, and rounds the result
+to the closest integer. Ties are rounded away from zero. Note that
+this is identical to using \verb|/| directly in an \meta{integer expression}.
+The result is returned as an \meta{integer denotation}.
+For example
+\begin{demohigh}
+\IntMathDiv {8} {3}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntMathDivTrancate}
+\begin{syntax}
+\cs{IntMathDivTrancate} \Arg{integer expression_1} \Arg{integer expression_2}
+\end{syntax}
+Evaluates the two \meta{integer expressions} as described earlier,
+then divides the first value by the second, and rounds the result towards zero.
+Note that division using \verb|/| rounds to the closest integer instead.
+The result is returned as an \meta{integer denotation}.
+For example
\begin{demohigh}
-\IntMathDiv{7}{3}
+\IntMathDivTruncate {8} {3}
\end{demohigh}
\end{function}
+\begin{function}{\IntMathSign}
+\begin{syntax}
+\cs{IntMathSign} \Arg{intexpr}
+\end{syntax}
+Evaluates the \meta{integer expression} then leaves $1$ or $0$ or
+$-1$ in the input stream according to the sign of the result.
+\end{function}
+
+\begin{function}{\IntMathAbs}
+\begin{syntax}
+\cs{IntMathAbs} \Arg{integer expression}
+\end{syntax}
+Evaluates the \meta{integer expression} as described for
+\cs{IntEval} and leaves the absolute value of the result in
+the input stream as an \meta{integer denotation} after two
+expansions.
+\end{function}
+
+\begin{function}{\IntMathMax,\IntMathMin}
+\begin{syntax}
+\cs{IntMathMax} \Arg{intexpr_1} \Arg{intexpr_2}
+\cs{IntMathMin} \Arg{intexpr_1} \Arg{intexpr_2}
+\end{syntax}
+Evaluates the \meta{integer expressions} as described for
+\cs{IntEval} and leaves either the larger or smaller value
+in the input stream as an \meta{integer denotation} after two
+expansions.
+\end{function}
+
+\begin{function}{\IntMathMod}
+\begin{syntax}
+\cs{IntMathMod} \Arg{intexpr_1} \Arg{intexpr_2}
+\end{syntax}
+Evaluates the two \meta{integer expressions} as described earlier,
+then calculates the integer remainder of dividing the first
+expression by the second. This is obtained by subtracting
+\cs{IntMathDivTruncate} \Arg{intexpr_1} \Arg{intexpr_2} times
+\meta{intexpr_2} from \meta{intexpr_1}. Thus, the result has the
+same sign as \meta{intexpr_1} and its absolute value is strictly
+less than that of \meta{intexpr_2}. The result is left in the input
+stream as an \meta{integer denotation} after two expansions.
+\end{function}
+
+\begin{function}{\IntMathRand}
+\begin{syntax}
+\cs{IntMathRand} \Arg{intexpr_1} \Arg{intexpr_2}
+\end{syntax}
+Evaluates the two \meta{integer expressions} and produces a
+pseudo-random number between the two (with bounds included).
+%This is not available in older versions of \XeTeX{}.
+\end{function}
+
+\section{Creating and Using Integers}
+
\begin{function}{\IntNew}
\begin{syntax}
\cs{IntNew} \meta{integer}
@@ -850,21 +2461,57 @@ already taken. The declaration is global. The \meta{integer} is
initially equal to $0$.
\end{function}
+\begin{function}{\IntConst}
+\begin{syntax}
+\cs{IntConst} \meta{integer} \Arg{integer expression}
+\end{syntax}
+Creates a new constant \meta{integer} or raises an error if the name
+is already taken. The value of the \meta{integer} is set
+globally to the \meta{integer expression}.
+\end{function}
+
\begin{function}{\IntUse}
\begin{syntax}
\cs{IntUse} \meta{integer}
\end{syntax}
Recovers the content of an \meta{integer} and returns the value.
-An error is raised if the variable does
-not exist or if it is invalid. Can be omitted in places where an
-\meta{integer} is required (such as in the first and third arguments
-of \cs{IntCompareTF}).%
-%\begin{texnote}
-%\cs{IntUse} is the \TeX{} primitive \tn{the}: this is one of
-%several \verb!functional! names for this primitive.
-%\end{texnote}
+An error is raised if the variable does not exist or if it is invalid.
+\end{function}
+
+\section{Viewing Integers}
+
+\begin{function}{\IntLog}
+\begin{syntax}
+\cs{IntLog} \Arg{integer expression}
+\end{syntax}
+Writes the result of evaluating the \meta{integer expression}
+in the log file.
+\end{function}
+
+\begin{function}{\IntVarLog}
+\begin{syntax}
+\cs{IntVarLog} \meta{integer}
+\end{syntax}
+Writes the value of the \meta{integer} in the log file.
+\end{function}
+
+\begin{function}{\IntShow}
+\begin{syntax}
+\cs{IntShow} \Arg{integer expression}
+\end{syntax}
+Displays the result of evaluating the \meta{integer expression}
+on the terminal.
+\end{function}
+
+\begin{function}{\IntVarShow}
+\begin{syntax}
+\cs{IntVarShow} \meta{integer}
+\end{syntax}
+Displays the value of the \meta{integer} on the terminal.
\end{function}
+\section{Setting Integer Variables}
+
\begin{function}{\IntSet}
\begin{syntax}
\cs{IntSet} \meta{integer} \Arg{integer expression}
@@ -873,23 +2520,40 @@ Sets \meta{integer} to the value of \meta{integer expression},
which must evaluate to an integer (as described for \cs{IntEval}).
For example
\begin{demohigh}
-\IntSet\lTmpaInt{3+5}
-\IntUse\lTmpaInt
+\IntSet \lTmpaInt {3+5}
+\IntUse \lTmpaInt
\end{demohigh}
\end{function}
+\begin{function}{\IntSetEq}
+\begin{syntax}
+\cs{IntSetEq} \meta{integer_1} \meta{integer_2}
+\end{syntax}
+Sets the content of \meta{integer_1} equal to that of
+\meta{integer_2}.
+\end{function}
+
\begin{function}{\IntZero}
\begin{syntax}
\cs{IntZero} \meta{integer}
\end{syntax}
Sets \meta{integer} to $0$. For example
\begin{demohigh}
-\IntSet\lTmpaInt{5}
-\IntZero\lTmpaInt
-\IntUse\lTmpaInt
+\IntSet \lTmpaInt {5}
+\IntZero \lTmpaInt
+\IntUse \lTmpaInt
\end{demohigh}
\end{function}
+\begin{function}{\IntZeroNew}
+\begin{syntax}
+\cs{IntZeroNew} \meta{integer}
+\end{syntax}
+Ensures that the \meta{integer} exists globally by applying
+\cs{IntNew} if necessary, then applies \cs{IntZero} to leave
+the \meta{integer} set to zero.
+\end{function}
+
\begin{function}{\IntIncr}
\begin{syntax}
\cs{IntIncr} \meta{integer}
@@ -897,9 +2561,9 @@ Sets \meta{integer} to $0$. For example
Increases the value stored in \meta{integer} by $1$.
For example
\begin{demohigh}
-\IntSet\lTmpaInt{5}
-\IntIncr\lTmpaInt
-\IntUse\lTmpaInt
+\IntSet \lTmpaInt {5}
+\IntIncr \lTmpaInt
+\IntUse \lTmpaInt
\end{demohigh}
\end{function}
@@ -910,9 +2574,9 @@ For example
Decreases the value stored in \meta{integer} by $1$.
For example
\begin{demohigh}
-\IntSet\lTmpaInt{5}
-\IntDecr\lTmpaInt
-\IntUse\lTmpaInt
+\IntSet \lTmpaInt {5}
+\IntDecr \lTmpaInt
+\IntUse \lTmpaInt
\end{demohigh}
\end{function}
@@ -923,9 +2587,9 @@ For example
Adds the result of the \meta{integer expression} to the current
content of the \meta{integer}. For example
\begin{demohigh}
-\IntSet\lTmpaInt{5}
-\IntAdd\lTmpaInt{2}
-\IntUse\lTmpaInt
+\IntSet \lTmpaInt {5}
+\IntAdd \lTmpaInt {2}
+\IntUse \lTmpaInt
\end{demohigh}
\end{function}
@@ -936,32 +2600,119 @@ content of the \meta{integer}. For example
Subtracts the result of the \meta{integer expression} from the
current content of the \meta{integer}. For example
\begin{demohigh}
-\IntSet\lTmpaInt{5}
-\IntSub\lTmpaInt{3}
-\IntUse\lTmpaInt
+\IntSet \lTmpaInt {5}
+\IntSub \lTmpaInt {3}
+\IntUse \lTmpaInt
\end{demohigh}
\end{function}
+\section{Integer Step Functions}
+
+%\begin{function}{\IntStepFunction}
+%\begin{syntax}
+%\cs{IntStepFunction} \Arg{initial value} \Arg{step} \Arg{final value} \meta{function}
+%\end{syntax}
+%This function first evaluates the \meta{initial value}, \meta{step}
+%and \meta{final value}, all of which should be integer expressions.
+%The \meta{function} is then placed in front of each \meta{value}
+%from the \meta{initial value} to the \meta{final value} in turn
+%(using \meta{step} between each \meta{value}). The \meta{step} must
+%be non-zero. If the \meta{step} is positive, the loop stops when
+%the \meta{value} becomes larger than the \meta{final value}. If the
+%\meta{step} is negative, the loop stops when the \meta{value}
+%becomes smaller than the \meta{final value}. The \meta{function}
+%should absorb one numerical argument. For example
+%\begin{verbatim}
+%\cs_set:Npn \my_func:n #1 { [I~saw~#1] \quad }
+%\int_step_function:nnnN { 1 } { 1 } { 5 } \my_func:n
+%\end{verbatim}
+%would print
+%\begin{quote}
+%[I saw 1] \quad
+%[I saw 2] \quad
+%[I saw 3] \quad
+%[I saw 4] \quad
+%[I saw 5] \quad
+%\end{quote}
+%\end{function}
+
+\begin{function}{\IntStepInline}
+\begin{syntax}
+\cs{IntStepInline} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code}
+\end{syntax}
+This function first evaluates the \meta{initial value}, \meta{step}
+and \meta{final value}, all of which should be integer expressions.
+Then for each \meta{value} from the \meta{initial value} to the
+\meta{final value} in turn (using \meta{step} between each
+\meta{value}), the \meta{code} is inserted into the input stream
+with \verb|#1| replaced by the current \meta{value}. Thus the
+\meta{code} should define a function of one argument~(\verb|#1|).
+For example
+\begin{codehigh}
+\IgnoreSpacesOn
+\TlClear \lTmpaTl
+\IntStepInline {1} {3} {30} {
+ \TlPutRight \lTmpaTl {[#1]}
+}
+\Result {\Value\lTmpaTl}
+\IgnoreSpacesOff
+\end{codehigh}
+produces [1][4][7][10][13][16][19][22][25][28].
+\end{function}
+
\begin{function}{\IntStepVariable}
\begin{syntax}
-\cs{IntStepVariable} \Arg{initial value} \Arg{step} \Arg{final value} \meta{tl~var} \Arg{code}
+\cs{IntStepVariable} \Arg{initial value} \Arg{step} \Arg{final value} \meta{tl var} \Arg{code}
\end{syntax}
This function first evaluates the \meta{initial value}, \meta{step}
and \meta{final value}, all of which should be integer expressions.
Then for each \meta{value} from the \meta{initial value} to the
\meta{final value} in turn (using \meta{step} between each
\meta{value}), the \meta{code} is evaluated,
-with the \meta{tl~var} defined as the current \meta{value}. Thus
+with the \meta{tl~var} defined as the current \meta{value}. Thus
the \meta{code} should make use of the \meta{tl~var}.
-For example
-\begin{demohigh}
-\TlClear\lTmpaTl
-\IntStepVariable{1}{3}{30}\lTmpiTl{
- \TlPutRight\lTmpaTl{\Value\lTmpiTl}
- \TlPutRight\lTmpaTl{ }
-}
-\Result{\Value\lTmpaTl}
-\end{demohigh}
+%For example
+%\begin{demohigh}
+%\IgnoreSpacesOn
+%\TlClear\lTmpaTl
+%\IntStepVariable{1}{3}{30}\lTmpiTl{
+% \TlPutRight\lTmpaTl{\Value\lTmpiTl}
+% \TlPutRight\lTmpaTl{~}
+%}
+%\Result{\Value\lTmpaTl}
+%\IgnoreSpacesOff
+%\end{demohigh}
+\end{function}
+
+\section{Integer Conditionals}
+
+\begin{function}{\IntIfExist, \IntIfExistTF}
+\begin{syntax}
+\cs{IntIfExist} \meta{integer}
+\cs{IntIfExistTF} \meta{integer} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests whether the \meta{integer} is currently defined. This does not
+check that the \meta{integer} really is an integer variable.
+\end{function}
+
+\begin{function}{\IntIfOdd,\IntIfOddTF}
+\begin{syntax}
+\cs{IntIfOdd} \Arg{integer expression}
+\cs{IntIfOddTF} \Arg{integer expression} \Arg{true code} \Arg{false code}
+\end{syntax}
+This function first evaluates the \meta{integer expression}
+as described for \cs{IntEval}.
+It then evaluates if this is odd or even, as appropriate.
+\end{function}
+
+\begin{function}{\IntIfEven,\IntIfEvenTF}
+\begin{syntax}
+\cs{IntIfEven} \Arg{integer expression}
+\cs{IntIfEvenTF} \Arg{integer expression} \Arg{true code} \Arg{false code}
+\end{syntax}
+This function first evaluates the \meta{integer expression}
+as described for \cs{IntEval}.
+It then evaluates if this is even or odd, as appropriate.
\end{function}
\begin{function}{\IntCompare,\IntCompareTF}
@@ -979,11 +2730,1632 @@ Less than & \texttt{<} \\
\end{tabular}\par}
For example
\begin{demohigh}
-\IntCompareTF{2}>{1}{\Result{Greater}}{\Result{Less}}
-\IntCompareTF{2}>{3}{\Result{Greater}}{\Result{Less}}
+\IntCompareTF {2} > {1} {\Result{Greater}} {\Result{Less}}
+\IntCompareTF {2} > {3} {\Result{Greater}} {\Result{Less}}
+\end{demohigh}
+\end{function}
+
+\section{Integer Case Functions}
+
+\begin{function}{\IntCase}
+\begin{syntax}
+\cs{IntCase} \Arg{test integer expression}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{intexpr case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{intexpr case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \Arg{intexpr case_n} \Arg{code case_n}
+~ ~ \verb|}|
+\end{syntax}
+This function evaluates the \meta{test integer expression} and
+compares this in turn to each of the
+\meta{integer expression cases}. If the two are equal then the
+associated \meta{code} is left in the input stream
+and other cases are discarded.
+\end{function}
+
+\begin{function}{\IntCaseT}
+\begin{syntax}
+\cs{IntCaseT} \Arg{test integer expression}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{intexpr case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{intexpr case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \Arg{intexpr case_n} \Arg{code case_n}
+~ ~ \verb|}|
+~ ~ \Arg{true code}
+\end{syntax}
+This function evaluates the \meta{test integer expression} and
+compares this in turn to each of the
+\meta{integer expression cases}. If the two are equal then the
+associated \meta{code} is left in the input stream
+and other cases are discarded. If any of the
+cases are matched, the \meta{true code} is also inserted into the
+input stream (after the code for the appropriate case).
+\end{function}
+
+\begin{function}{\IntCaseF}
+\begin{syntax}
+\cs{IntCaseF} \Arg{test integer expression}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{intexpr case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{intexpr case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \Arg{intexpr case_n} \Arg{code case_n}
+~ ~ \verb|}|
+~ ~ \Arg{false code}
+\end{syntax}
+This function evaluates the \meta{test integer expression} and
+compares this in turn to each of the
+\meta{integer expression cases}. If the two are equal then the
+associated \meta{code} is left in the input stream
+and other cases are discarded. If none
+match then the \meta{false code} is into the input stream
+(after the code for the appropriate case).
+For example
+\begin{demohigh}
+\IgnoreSpacesOn
+\IntCaseF { 2 * 5 }
+ {
+ { 5 } { Small }
+ { 4 + 6 } { Medium }
+ { -2 * 10 } { Negative }
+ }
+ { No idea! }
+\IgnoreSpacesOff
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntCaseTF}
+\begin{syntax}
+\cs{IntCaseTF} \Arg{test integer expression}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{intexpr case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{intexpr case_2} \Arg{code case_2}
+~ ~ ~ ~ $\cdots$
+~ ~ ~ ~ \Arg{intexpr case_n} \Arg{code case_n}
+~ ~ \verb|}|
+~ ~ \Arg{true code}
+~ ~ \Arg{false code}
+\end{syntax}
+This function evaluates the \meta{test integer expression} and
+compares this in turn to each of the
+\meta{integer expression cases}. If the two are equal then the
+associated \meta{code} is left in the input stream
+and other cases are discarded. If any of the
+cases are matched, the \meta{true code} is also inserted into the
+input stream (after the code for the appropriate case), while if none
+match then the \meta{false code} is inserted.
+\end{function}
+
+\chapter{Floating Point Numbers (\texttt{Fp})}
+
+\section{Constant and Scratch Floating Points}
+
+\begin{variable}{\cZeroFp, \cMinusZeroFp}
+Zero, with either sign.
+\end{variable}
+
+\begin{variable}{\cOneFp}
+One as an \texttt{fp}: useful for comparisons in some places.
+\end{variable}
+
+\begin{variable}{\cInfFp,\cMinusInfFp}
+Infinity, with either sign. These can be input directly in a
+floating point expression as \texttt{inf} and \texttt{-inf}.
+\end{variable}
+
+\begin{variable}{\cEFp}
+The value of the base of the natural logarithm, $\mathrm{e} = \exp(1)$.
+\end{variable}
+
+\begin{variable}{\cPiFp}
+The value of $\pi$. This can be input directly in a floating point
+expression as \texttt{pi}.
+\end{variable}
+
+\begin{variable}{\cOneDegreeFp}
+The value of $1^{\circ}$ in radians. Multiply an angle given in
+degrees by this value to obtain a result in radians. Note that
+trigonometric functions expecting an argument in radians or in
+degrees are both available. Within floating point expressions, this
+can be accessed as \texttt{deg}.
+\end{variable}
+
+\begin{variable}{\lTmpaFp,\lTmpbFp,\lTmpcFp,\lTmpiFp,\lTmpjFp,\lTmpkFp}
+Scratch floating point numbers for local assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\begin{variable}{\gTmpaFp,\gTmpbFp,\gTmpcFp,\gTmpiFp,\gTmpjFp,\gTmpkFp}
+Scratch floating point numbers for global assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\section{Floating Point Expressions}
+
+\begin{function}{\FpEval}
+\begin{syntax}
+\cs{FpEval} \Arg{floating point expression}
+\end{syntax}
+Evaluates the \meta{floating point expression} and returns the
+result as a decimal number with no
+exponent. Leading or trailing zeros may be inserted to compensate
+for the exponent. Non-significant trailing zeros are trimmed, and
+integers are expressed without a decimal separator. The values
+$\pm\infty$ and \nan{} trigger an \enquote{invalid operation}
+exception.
+For a tuple, each item is converted using \cs{FpEval} and they are combined as
+\verb|(|\meta{fp_1}\verb*|, |\meta{fp_2}\verb*|, |\ldots{}\meta{fp_n}\verb|)|
+if $n>1$ and \verb|(|\meta{fp_1}\verb|,)| or \verb|()| for fewer items.
+%This function is identical to \cs{fp_to_decimal:n}.
+For example
+\begin{demohigh}
+\FpEval {(1.2+3.4)*(5.6-7.8)/9}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\FpMathAdd}
+\begin{syntax}
+\cs{FpMathAdd} \Arg{fpexpr_1} \Arg{fpexpr_2}
+\end{syntax}
+Adds \Arg{fpexpr_1} and \Arg{fpexpr_2},
+and returns the result. For example
+\begin{demohigh}
+\FpMathAdd {2.8} {3.7}
+\FpMathAdd {3.8-1} {2.7+1}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\FpMathSub}
+\begin{syntax}
+\cs{FpMathSub} \Arg{fpexpr_1} \Arg{fpexpr_2}
+\end{syntax}
+Subtracts \Arg{fpexpr_2} from \Arg{fpexpr_1},
+and returns the result. For example
+\begin{demohigh}
+\FpMathSub {2.8} {3.7}
+\FpMathSub {3.8-1} {2.7+1}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\FpMathMult}
+\begin{syntax}
+\cs{FpMathMult} \Arg{fpexpr_1} \Arg{fpexpr_2}
+\end{syntax}
+Multiplies \Arg{fpexpr_1} by \Arg{fpexpr_2},
+and returns the result. For example
+\begin{demohigh}
+\FpMathMult {2.8} {3.7}
+\FpMathMult {3.8-1} {2.7+1}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\FpMathDiv}
+\begin{syntax}
+\cs{FpMathDiv} \Arg{fpexpr_1} \Arg{fpexpr_2}
+\end{syntax}
+Divides \Arg{fpexpr_1} by \Arg{fpexpr_2},
+and returns the result. For example
+\begin{demohigh}
+\FpMathDiv {2.8} {3.7}
+\FpMathDiv {3.8-1} {2.7+1}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\FpMathSign}
+\begin{syntax}
+\cs{FpMathSign} \Arg{fpexpr}
+\end{syntax}
+Evaluates the \meta{fpexpr} and returns the value
+using \cs{FpEval}\verb|{sign(|\meta{result}\verb|)}|: $+1$ for positive
+numbers and for $+\infty$, $-1$ for negative numbers and for
+$-\infty$, $\pm 0$ for $\pm 0$. If the operand is a tuple or is
+\nan{}, then \enquote{invalid operation} occurs and the result
+is $0$. For example
+\begin{demohigh}
+\FpMathSign {3.5}
+\FpMathSign {-2.7}
\end{demohigh}
\end{function}
+\begin{function}{\FpMathAbs}
+\begin{syntax}
+\cs{FpMathAbs} \Arg{floating point expression}
+\end{syntax}
+Evaluates the \meta{floating point expression} as described for
+\cs{FpEval} and returns the absolute value.
+If the argument is $\pm\infty$, \nan{} or a tuple,
+\enquote{invalid operation} occurs. Within floating point
+expressions, \verb|abs()| can be used; it accepts $\pm\infty$ and \nan{}
+as arguments.
+\end{function}
+
+\begin{function}{\FpMathMax,\FpMathMin}
+\begin{syntax}
+\cs{FpMathMax} \Arg{fp expression_1} \Arg{fp expression_2}
+\cs{FpMathMin} \Arg{fp expression_1} \Arg{fp expression_2}
+\end{syntax}
+Evaluates the \meta{floating point expressions} as described for \cs{FpEval}
+and returns the resulting larger (\texttt{max}) or smaller (\texttt{min}) value.
+If the argument is a tuple, \enquote{invalid operation} occurs,
+but no other case raises exceptions. Within floating point expressions,
+\verb|max()| and \verb|min()| can be used.
+\end{function}
+
+\section{Creating and Using Floating Points}
+
+\begin{function}{\FpNew}
+\begin{syntax}
+\cs{FpNew} \meta{fp var}
+\end{syntax}
+Creates a new \meta{fp var} or raises an error if the name is
+already taken. The declaration is global. The \meta{fp~var} is
+initially $+0$.
+\end{function}
+
+\begin{function}{\FpConst}
+\begin{syntax}
+\cs{FpConst} \meta{fp var} \Arg{floating point expression}
+\end{syntax}
+Creates a new constant \meta{fp var} or raises an error if the name
+is already taken. The \meta{fp var} is set globally equal to
+the result of evaluating the \meta{floating point expression}.
+For example
+\begin{demohigh}
+\FpConst \cMyPiFp {3.1415926}
+\FpUse \cMyPiFp
+\end{demohigh}
+\end{function}
+
+\begin{function}{\FpUse}
+\begin{syntax}
+\cs{FpUse} \meta{fp var}
+\end{syntax}
+Recovers the value of the \meta{fp var} and returns the value as a
+decimal number with no exponent.
+%Leading or trailing zeros may be inserted to compensate for the
+%exponent. Non-significant trailing zeros are trimmed. Integers are
+%expressed without a decimal separator. The values $\pm\infty$
+%and \nan{} trigger an \enquote{invalid operation} exception.
+%For a tuple, each item is converted using \cs{fp_to_decimal:n} and they are combined as
+%|(|\meta{fp_1}\verb*|, |\meta{fp_2}\verb*|, |\ldots{}\meta{fp_n}|)|
+%if $n>1$ and |(|\meta{fp_1}|,)| or |()| for fewer items.
+%This function is identical to \cs{fp_to_decimal:N}.
+\end{function}
+
+\section{Viewing Floating Points}
+
+\begin{function}{\FpLog}
+\begin{syntax}
+\cs{FpLog} \Arg{floating point expression}
+\end{syntax}
+Evaluates the \meta{floating point expression} and writes the
+result in the log file.
+\end{function}
+
+\begin{function}{\FpVarLog}
+\begin{syntax}
+\cs{FpVarLog} \meta{fp var}
+\end{syntax}
+Writes the value of \meta{fp var} in the log file.
+\end{function}
+
+\begin{function}{\FpShow}
+\begin{syntax}
+\cs{FpShow} \Arg{floating point expression}
+\end{syntax}
+Evaluates the \meta{floating point expression} and displays the
+result in the terminal.
+\end{function}
+
+\begin{function}{\FpVarShow}
+\begin{syntax}
+\cs{FpVarShow} \meta{fp var}
+\end{syntax}
+Displays the value of \meta{fp var} in the terminal.
+\end{function}
+
+\section{Setting Floating Point Variables}
+
+\begin{function}{\FpSet}
+\begin{syntax}
+\cs{FpSet} \meta{fp var} \Arg{floating point expression}
+\end{syntax}
+Sets \meta{fp var} equal to the result of computing the
+\meta{floating point expression}. For example
+\begin{demohigh}
+\FpSet \lTmpaFp {4/7}
+\FpUse \lTmpaFp
+\end{demohigh}
+\end{function}
+
+\begin{function}{\FpSetEq}
+\begin{syntax}
+\cs{FpSetEq} \meta{fp var_1} \meta{fp var_2}
+\end{syntax}
+Sets the floating point variable \meta{fp var_1} equal to the current
+value of \meta{fp var_2}.
+\end{function}
+
+\begin{function}{\FpZero}
+\begin{syntax}
+\cs{FpZero} \meta{fp var}
+\end{syntax}
+Sets the \meta{fp var} to $+0$. For example
+\begin{demohigh}
+\FpSet \lTmpaFp {5.3}
+\FpZero \lTmpaFp
+\FpUse \lTmpaFp
+\end{demohigh}
+\end{function}
+
+\begin{function}{\FpZeroNew}
+\begin{syntax}
+\cs{FpZeroNew} \meta{fp var}
+\end{syntax}
+Ensures that the \meta{fp var} exists globally
+by applying \cs{FpNew} if necessary, then applies
+\cs{FpZero} to leave the \meta{fp var} set to $+0$.
+\end{function}
+
+\begin{function}{\FpAdd}
+\begin{syntax}
+\cs{FpAdd} \meta{fp var} \Arg{floating point expression}
+\end{syntax}
+Adds the result of computing the \meta{floating point expression} to
+the \meta{fp var}.
+This also applies if \meta{fp var} and \meta{floating point
+expression} evaluate to tuples of the same size. For example
+\begin{demohigh}
+\FpSet \lTmpaFp {5.3}
+\FpAdd \lTmpaFp {2.11}
+\FpUse \lTmpaFp
+\end{demohigh}
+\end{function}
+
+\begin{function}{\FpSub}
+\begin{syntax}
+\cs{FpSub} \meta{fp var} \Arg{floating point expression}
+\end{syntax}
+Subtracts the result of computing the \meta{floating point
+expression} from the \meta{fp var}.
+This also applies if \meta{fp var} and \meta{floating point
+expression} evaluate to tuples of the same size. For example
+\begin{demohigh}
+\FpSet \lTmpaFp {5.3}
+\FpSub \lTmpaFp {2.11}
+\FpUse \lTmpaFp
+\end{demohigh}
+\end{function}
+
+\section{Floating Point Step Functions}
+
+%\begin{function}{\FpStepFunction}
+%\begin{syntax}
+%\cs{FpStepFunction} \Arg{initial value} \Arg{step} \Arg{final value} \meta{function}
+%\end{syntax}
+%This function first evaluates the \meta{initial value}, \meta{step}
+%and \meta{final value}, each of which should be a floating point
+%expression evaluating to a floating point number, not a tuple.
+%The \meta{function} is then placed in front of each \meta{value}
+%from the \meta{initial value} to the \meta{final value} in turn
+%(using \meta{step} between each \meta{value}). The \meta{step} must
+%be non-zero. If the \meta{step} is positive, the loop stops when
+%the \meta{value} becomes larger than the \meta{final value}. If the
+%\meta{step} is negative, the loop stops when the \meta{value}
+%becomes smaller than the \meta{final value}. The \meta{function}
+%should absorb one numerical argument. For example
+%\begin{verbatim}
+%\cs_set:Npn \my_func:n #1 { [I saw #1] \quad }
+%\fp_step_function:nnnN { 1.0 } { 0.1 } { 1.5 } \my_func:n
+%\end{verbatim}
+%would print
+%\begin{quote}
+%[I saw 1.0] \quad
+%[I saw 1.1] \quad
+%[I saw 1.2] \quad
+%[I saw 1.3] \quad
+%[I saw 1.4] \quad
+%[I saw 1.5] \quad
+%\end{quote}
+%\begin{texnote}
+%Due to rounding, it may happen that adding the \meta{step} to the
+%\meta{value} does not change the \meta{value}; such cases give an
+%error, as they would otherwise lead to an infinite loop.
+%\end{texnote}
+%\end{function}
+
+\begin{function}{\FpStepInline}
+\begin{syntax}
+\cs{FpStepInline} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code}
+\end{syntax}
+This function first evaluates the \meta{initial value}, \meta{step}
+and \meta{final value}, all of which should be floating point
+expressions evaluating to a floating point number, not a tuple.
+Then for each \meta{value} from the \meta{initial value} to the
+\meta{final value} in turn (using \meta{step} between each
+\meta{value}), the \meta{code} is inserted into the input stream
+with \verb|#1| replaced by the current \meta{value}. Thus the
+\meta{code} should define a function of one argument (\verb|#1|).
+For example
+\begin{codehigh}
+\IgnoreSpacesOn
+\TlClear \lTmpaTl
+\FpStepInline {1} {0.1} {1.5} {
+ \TlPutRight \lTmpaTl {[#1]}
+}
+\Result {\Value\lTmpaTl}
+\IgnoreSpacesOff
+\end{codehigh}
+produces [1][1.1][1.2][1.3][1.4][1.5].
+\end{function}
+
+\begin{function}{\FpStepVariable}
+\begin{syntax}
+\cs{FpStepVariable} \Arg{initial value} \Arg{step} \Arg{final value} \meta{tl var} \Arg{code}
+\end{syntax}
+This function first evaluates the \meta{initial value}, \meta{step}
+and \meta{final value}, all of which should be floating point
+expressions evaluating to a floating point number, not a tuple.
+Then for each \meta{value} from the \meta{initial value} to the
+\meta{final value} in turn (using \meta{step} between each
+\meta{value}), the \meta{code} is inserted into the input stream,
+with the \meta{tl var} defined as the current \meta{value}. Thus
+the \meta{code} should make use of the \meta{tl var}.
+%For example
+%\begin{demohigh}
+%\IgnoreSpacesOn
+%\TlClear\lTmpaTl
+%\FpStepVariable{1}{0.1}{1.5}\lTmpiTl{
+% \TlPutRight\lTmpaTl{\Value\lTmpiTl}
+% \TlPutRight\lTmpaTl{~}
+%}
+%\Result{\Value\lTmpaTl}
+%\IgnoreSpacesOff
+%\end{demohigh}
+\end{function}
+
+\section{Float Point Conditionals}
+
+\begin{function}{\FpIfExist,\FpIfExistTF}
+\begin{syntax}
+\cs{FpIfExist} \meta{fp var}
+\cs{FpIfExistTF} \meta{fp var} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests whether the \meta{fp var} is currently defined. This does not
+check that the \meta{fp var} really is a floating point variable.
+For example
+\begin{demohigh}
+\FpIfExistTF \lTmpaFp {\Result{Yes}} {\Result{No}}
+\FpIfExistTF \lMyUndefinedFp {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\FpCompare,\FpCompareTF}
+\begin{syntax}
+\cs{FpCompare} \Arg{fpexpr_1} \meta{relation} \Arg{fpexpr_2}
+\cs{FpCompareTF} \Arg{fpexpr_1} \meta{relation} \Arg{fpexpr_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Compares the \meta{fpexpr_1} and the \meta{fpexpr_2}, and returns
+\texttt{true} if the \meta{relation} is obeyed. For example
+\begin{demohigh}
+\FpCompareTF {1} > {0.9999} {\Result{Greater}} {\Result{Less}}
+\FpCompareTF {1} > {1.0001} {\Result{Greater}} {\Result{Less}}
+\end{demohigh}
+Two floating points
+$x$ and $y$ may obey four mutually exclusive relations:
+$x<y$, $x=y$, $x>y$, or $x?y$ (\enquote{not ordered}). The last
+case occurs exactly if one or both operands is \nan{} or is a tuple,
+unless they are equal tuples. Note that a \nan{} is distinct from
+any value, even another \nan{}, hence $x=x$ is not true for
+a \nan{}. To test if a value is \nan{}, compare it to an arbitrary
+number with the \enquote{not ordered} relation.\par
+%\begin{demohigh}
+%\FpCompareTF{0/0}?{0}{\Result{Is~a~Nan}}{\Result{Isn't~a~NaN}}
+%\end{demohigh}
+Tuples are equal if they have the same number of items and items
+compare equal (in particular there must be no \nan{}).
+At present any other comparison with tuples yields \verb|?| (not ordered).
+This is experimental.
+\end{function}
+
+\chapter{Dimensions (\texttt{Dim})}
+
+\section{Constant and Scratch Dimensions}
+
+\begin{variable}{\cMaxDim}
+The maximum value that can be stored as a dimension. This can also
+be used as a component of a skip.
+\end{variable}
+
+\begin{variable}{\cZeroDim}
+A zero length as a dimension. This can also be used as a component
+of a skip.
+\end{variable}
+
+\begin{variable}{\lTmpaDim,\lTmpbDim,\lTmpcDim,\lTmpiDim,\lTmpjDim,\lTmpkDim}
+Scratch dimensions for local assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\begin{variable}{\gTmpaDim,\gTmpbDim,\gTmpcDim,\gTmpiDim,\gTmpjDim,\gTmpkDim}
+Scratch dimensions for global assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\section{Dimension Expressions}
+
+\begin{function}{\DimEval}
+\begin{syntax}
+\cs{DimEval} \Arg{dimension expression}
+\end{syntax}
+Evaluates the \meta{dimension expression}, expanding any
+dimensions and token list variables within the \meta{expression}
+to their content (without requiring \cs{DimUse}/\cs{TlUse})
+and applying the standard mathematical rules. The result of the
+calculation is returned as a \meta{dimension denotation}.
+%This is expressed in points (\texttt{pt}), and requires suitable
+%termination if used in a \TeX{}-style assignment as it is \emph{not}
+%an \meta{internal dimension}.
+For example
+\begin{demohigh}
+\DimEval {(1.2pt+3.4pt)/9}
+\end{demohigh}
+%\DimEval{(1.2pt+3.4pt)*(5.6-7.8)/9}
+\end{function}
+
+\begin{function}{\DimMathAdd}
+\begin{syntax}
+\cs{DimMathAdd} \Arg{dimexpr_1} \Arg{dimexpr_2}
+\end{syntax}
+Adds \Arg{dimexpr_1} and \Arg{dimexpr_2},
+and returns the result. For example
+\begin{demohigh}
+\DimMathAdd {2.8pt} {3.7pt}
+\DimMathAdd {3.8pt-1pt} {2.7pt+1pt}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimMathSub}
+\begin{syntax}
+\cs{DimMathSub} \Arg{dimexpr_1} \Arg{dimexpr_2}
+\end{syntax}
+Subtracts \Arg{dimexpr_2} from \Arg{dimexpr_1},
+and returns the result. For example
+\begin{demohigh}
+\DimMathSub {2.8pt} {3.7pt}
+\DimMathSub {3.8pt-1pt} {2.7pt+1pt}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimMathRatio}
+\begin{syntax}
+\cs{DimMathRatio} \Arg{dimexpr_1} \Arg{dimexpr_2}
+\end{syntax}
+Parses the two \meta{dimension expressions},
+then calculates the ratio of the two and returns it.
+The result is a ratio expression
+between two integers, with all distances converted to scaled points.
+For example
+\begin{demohigh}
+\DimMathRatio {5pt} {10pt}
+\end{demohigh}
+The returned value is suitable for use inside a \meta{dimension expression}
+such as
+\begin{codehigh}
+\DimSet \lTmpaDim {10pt*\DimMathRatio{5pt}{10pt}}
+\end{codehigh}
+\end{function}
+
+\begin{function}{\DimMathSign}
+\begin{syntax}
+\cs{DimMathSign} \Arg{dimexpr}
+\end{syntax}
+Evaluates the \meta{dimexpr} then returns $1$ or $0$ or $-1$
+according to the sign of the result. For example
+\begin{demohigh}
+\DimMathSign {3.5pt}
+\DimMathSign {-2.7pt}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimMathAbs}
+\begin{syntax}
+\cs{DimMathAbs} \Arg{dimexpr}
+\end{syntax}
+Converts the \meta{dimexpr} to its absolute value,
+returning the result as a \meta{dimension denotation}.
+For example
+\begin{demohigh}
+\DimMathAbs {3.5pt}
+\DimMathAbs {-2.7pt}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimMathMax,\DimMathMin}
+\begin{syntax}
+\cs{DimMathMax} \Arg{dimexpr_1} \Arg{dimexpr_2}
+\cs{DimMathMin} \Arg{dimexpr_1} \Arg{dimexpr_2}
+\end{syntax}
+Evaluates the two \meta{dimension expressions} and returns either the
+maximum or minimum value as appropriate as a \meta{dimension denotation}.
+For example
+\begin{demohigh}
+\DimMathMax {3.5pt} {-2.7pt}
+\DimMathMin {3.5pt} {-2.7pt}
+\end{demohigh}
+\end{function}
+
+\section{Creating and Using Dimensions}
+
+\begin{function}{\DimNew}
+\begin{syntax}
+\cs{DimNew} \meta{dimension}
+\end{syntax}
+Creates a new \meta{dimension} or raises an error if the name is
+already taken. The declaration is global. The \meta{dimension}
+is initially equal to $0$\,pt.
+\end{function}
+
+\begin{function}{\DimConst}
+\begin{syntax}
+\cs{DimConst} \meta{dimension} \Arg{dimension expression}
+\end{syntax}
+Creates a new constant \meta{dimension} or raises an error if the
+name is already taken. The value of the \meta{dimension} is set
+globally to the \meta{dimension expression}. For example
+\begin{demohigh}
+\DimConst \cFooSomeDim {1cm}
+\DimUse \cFooSomeDim
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimUse}
+\begin{syntax}
+\cs{DimUse} \meta{dimension}
+\end{syntax}
+Recovers the content of a \meta{dimension} and returns the value.
+An error is raised if the variable does not exist or if it is invalid.
+\end{function}
+
+\section{Viewing Dimensions}
+
+\begin{function}{\DimLog}
+\begin{syntax}
+\cs{DimLog} \Arg{dimension expression}
+\end{syntax}
+Writes the result of evaluating the \meta{dimension expression}
+in the log file. For example
+\begin{codehigh}
+\DimLog {\lFooSomeDim+1cm}
+\end{codehigh}
+\end{function}
+
+\begin{function}{\DimVarLog}
+\begin{syntax}
+\cs{DimVarLog} \meta{dimension}
+\end{syntax}
+Writes the value of the \meta{dimension} in the log file. For example
+\begin{codehigh}
+\DimVarLog \lFooSomeDim
+\end{codehigh}
+\end{function}
+
+\begin{function}{\DimShow}
+\begin{syntax}
+\cs{DimShow} \Arg{dimension expression}
+\end{syntax}
+Displays the result of evaluating the \meta{dimension expression}
+on the terminal. For example
+\begin{codehigh}
+\DimShow {\lFooSomeDim+1cm}
+\end{codehigh}
+\end{function}
+
+\begin{function}{\DimVarShow}
+\begin{syntax}
+\cs{DimVarShow} \meta{dimension}
+\end{syntax}
+Displays the value of the \meta{dimension} on the terminal. For example
+\begin{codehigh}
+\DimVarShow \lFooSomeDim
+\end{codehigh}
+\end{function}
+
+\section{Setting Dimension Variables}
+
+\begin{function}{\DimSet}
+\begin{syntax}
+\cs{DimSet} \meta{dimension} \Arg{dimension expression}
+\end{syntax}
+Sets \meta{dimension} to the value of \meta{dimension expression}, which
+must evaluate to a length with units.
+\end{function}
+
+\begin{function}{\DimSetEq}
+\begin{syntax}
+\cs{DimSetEq} \meta{dimension_1} \meta{dimension_2}
+\end{syntax}
+Sets the content of \meta{dimension_1} equal to that of
+\meta{dimension_2}. For example
+\begin{demohigh}
+\DimSet \lTmpaDim {10pt}
+\DimSetEq \lTmpbDim \lTmpaDim
+\DimUse \lTmpbDim
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimZero}
+\begin{syntax}
+\cs{DimZero} \meta{dimension}
+\end{syntax}
+Sets \meta{dimension} to $0$\,pt. For example
+\begin{demohigh}
+\DimSet \lTmpaDim {1em}
+\DimZero \lTmpaDim
+\DimUse \lTmpaDim
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimZeroNew}
+\begin{syntax}
+\cs{DimZeroNew} \meta{dimension}
+\end{syntax}
+Ensures that the \meta{dimension} exists globally by applying
+\cs{DimNew} if necessary, then applies
+\cs{DimZero} to set the \meta{dimension} to zero. For example
+\begin{demohigh}
+\DimZeroNew \lFooSomeDim
+\DimUse \lFooSomeDim
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimAdd}
+\begin{syntax}
+\cs{DimAdd} \meta{dimension} \Arg{dimension expression}
+\end{syntax}
+Adds the result of the \meta{dimension expression} to the current
+content of the \meta{dimension}. For example
+\begin{demohigh}
+\DimSet \lTmpaDim {5.3pt}
+\DimAdd \lTmpaDim {2.11pt}
+\DimUse \lTmpaDim
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimSub}
+\begin{syntax}
+\cs{DimSub} \meta{dimension} \Arg{dimension expression}
+\end{syntax}
+Subtracts the result of the \meta{dimension expression} from the
+current content of the \meta{dimension}. For example
+\begin{demohigh}
+\DimSet \lTmpaDim {5.3pt}
+\DimSub \lTmpaDim {2.11pt}
+\DimUse \lTmpaDim
+\end{demohigh}
+\end{function}
+
+\section{Dimension Step Functions}
+
+%\begin{function}{\DimStepFunction}
+%\begin{syntax}
+%\cs{DimStepFunction} \Arg{initial value} \Arg{step} \Arg{final value} \meta{function}
+%\end{syntax}
+%This function first evaluates the \meta{initial value}, \meta{step}
+%and \meta{final value}, all of which should be dimension expressions.
+%The \meta{function} is then placed in front of each \meta{value}
+%from the \meta{initial value} to the \meta{final value} in turn
+%(using \meta{step} between each \meta{value}). The \meta{step} must
+%be non-zero. If the \meta{step} is positive, the loop stops when
+%the \meta{value} becomes larger than the \meta{final value}. If the
+%\meta{step} is negative, the loop stops when the \meta{value}
+%becomes smaller than the \meta{final value}. The \meta{function}
+%should absorb one argument.
+%\end{function}
+
+\begin{function}{\DimStepInline}
+\begin{syntax}
+\cs{DimStepInline} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code}
+\end{syntax}
+This function first evaluates the \meta{initial value}, \meta{step}
+and \meta{final value}, all of which should be dimension expressions.
+Then for each \meta{value} from the \meta{initial value} to the
+\meta{final value} in turn (using \meta{step} between each
+\meta{value}), the \meta{code} is inserted into the input stream
+with \verb|#1| replaced by the current \meta{value}. Thus the
+\meta{code} should define a function of one argument (\verb|#1|).
+For example
+\begin{codehigh}
+\IgnoreSpacesOn
+\TlClear \lTmpaTl
+\DimStepInline {1pt} {0.1pt} {1.5pt} {
+ \TlPutRight \lTmpaTl {[#1]}
+}
+\Result {\Value\lTmpaTl}
+\IgnoreSpacesOff
+\end{codehigh}
+produces [1.0pt][1.1pt][1.20001pt][1.30002pt][1.40002pt].
+\end{function}
+
+\begin{function}{\DimStepVariable}
+\begin{syntax}
+\cs{DimStepVariable} \Arg{initial value} \Arg{step} \Arg{final value} \meta{tl var} \Arg{code}
+\end{syntax}
+This function first evaluates the \meta{initial value}, \meta{step}
+and \meta{final value}, all of which should be dimension expressions.
+Then for each \meta{value} from the \meta{initial value} to the
+\meta{final value} in turn (using \meta{step} between each
+\meta{value}), the \meta{code} is inserted into the input stream,
+with the \meta{tl var} defined as the current \meta{value}. Thus
+the \meta{code} should make use of the \meta{tl var}.
+%For example
+%\begin{demohigh}
+%\IgnoreSpacesOn
+%\TlClear\lTmpaTl
+%\DimStepVariable{1pt}{0.1pt}{1.5pt}\lTmpiTl{
+% \TlPutRight\lTmpaTl{\Value\lTmpiTl}
+% \TlPutRight\lTmpaTl{~}
+%}
+%\Result{\Value\lTmpaTl}
+%\IgnoreSpacesOff
+%\end{demohigh}
+\end{function}
+
+\section{Dimension Conditionals}
+
+\begin{function}{\DimIfExist,\DimIfExistTF}
+\begin{syntax}
+\cs{DimIfExist} \meta{dimension}
+\cs{DimIfExistTF} \meta{dimension} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests whether the \meta{dimension} is currently defined. This does
+not check that the \meta{dimension} really is a dimension variable.
+For example
+\begin{demohigh}
+\DimIfExistTF \lTmpaDim {\Result{Yes}} {\Result{No}}
+\DimIfExistTF \lFooUndefinedDim {\Result{Yes}} {\Result{No}}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimCompare,\DimCompareTF}
+\begin{syntax}
+\cs{DimCompare} \Arg{dimexpr_1} \meta{relation} \Arg{dimexpr_2}
+\cs{DimCompareTF} \Arg{dimexpr_1} \meta{relation} \Arg{dimexpr_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+This function first evaluates each of the \meta{dimension expressions}
+as described for \cs{DimEval}. The two results are then
+compared using the \meta{relation}:\par
+{\centering
+\begin{tabular}{ll}
+Equal & \verb|=| \\
+Greater than & \verb|>| \\
+Less than & \verb|<| \\
+\end{tabular}\par}
+For example
+\begin{demohigh}
+\DimCompareTF {1pt} > {0.9999pt} {\Result{Greater}} {\Result{Less}}
+\DimCompareTF {1pt} > {1.0001pt} {\Result{Greater}} {\Result{Less}}
+\end{demohigh}
+\end{function}
+
+\section{Dimension Case Functions}
+
+\begin{function}{\DimCase}
+\begin{syntax}
+\cs{DimCase} \Arg{test dimension expression}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{dimexpr case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{dimexpr case_2} \Arg{code case_2}
+~ ~ ~ ~ \ldots
+~ ~ ~ ~ \Arg{dimexpr case_n} \Arg{code case_n}
+~ ~ \verb|}|
+\end{syntax}
+This function evaluates the \meta{test dimension expression} and
+compares this in turn to each of the
+\meta{dimension expression cases}. If the two are equal then the
+associated \meta{code} is left in the input stream
+and other cases are discarded.
+\end{function}
+
+\begin{function}{\DimCaseT}
+\begin{syntax}
+\cs{DimCaseT} \Arg{test dimension expression}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{dimexpr case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{dimexpr case_2} \Arg{code case_2}
+~ ~ ~ ~ \ldots
+~ ~ ~ ~ \Arg{dimexpr case_n} \Arg{code case_n}
+~ ~ \verb|}|
+~ ~ \Arg{true code}
+\end{syntax}
+This function evaluates the \meta{test dimension expression} and
+compares this in turn to each of the
+\meta{dimension expression cases}. If the two are equal then the
+associated \meta{code} is left in the input stream
+and other cases are discarded. If any of the
+cases are matched, the \meta{true code} is also inserted into the
+input stream (after the code for the appropriate case).
+\end{function}
+
+\begin{function}{\DimCaseF}
+\begin{syntax}
+\cs{DimCaseF} \Arg{test dimension expression}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{dimexpr case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{dimexpr case_2} \Arg{code case_2}
+~ ~ ~ ~ \ldots
+~ ~ ~ ~ \Arg{dimexpr case_n} \Arg{code case_n}
+~ ~ \verb|}|
+~ ~ \Arg{false code}
+\end{syntax}
+This function evaluates the \meta{test dimension expression} and
+compares this in turn to each of the
+\meta{dimension expression cases}. If the two are equal then the
+associated \meta{code} is left in the input stream
+and other cases are discarded. If none of the cases
+match then the \meta{false code} is inserted.
+For example
+\begin{demohigh}
+\IgnoreSpacesOn
+\DimSet \lTmpaDim {5pt}
+\DimCaseF {2\lTmpaDim} {
+ {5pt} {\Result{Small}}
+ {4pt+6pt} {\Result{Medium}}
+ {-10pt} {\Result{Negative}}
+}{
+ \Result {No Match}
+}
+\IgnoreSpacesOff
+\end{demohigh}
+\end{function}
+
+\begin{function}{\DimCaseTF}
+\begin{syntax}
+\cs{DimCaseTF} \Arg{test dimension expression}
+~ ~ \verb|{|
+~ ~ ~ ~ \Arg{dimexpr case_1} \Arg{code case_1}
+~ ~ ~ ~ \Arg{dimexpr case_2} \Arg{code case_2}
+~ ~ ~ ~ \ldots
+~ ~ ~ ~ \Arg{dimexpr case_n} \Arg{code case_n}
+~ ~ \verb|}|
+~ ~ \Arg{true code}
+~ ~ \Arg{false code}
+\end{syntax}
+This function evaluates the \meta{test dimension expression} and
+compares this in turn to each of the
+\meta{dimension expression cases}. If the two are equal then the
+associated \meta{code} is left in the input stream
+and other cases are discarded. If any of the
+cases are matched, the \meta{true code} is also inserted into the
+input stream (after the code for the appropriate case), while if none
+match then the \meta{false code} is inserted.
+%For example
+%\begin{demohigh}
+%\IgnoreSpacesOn
+%\DimSet\lTmpaDim{5pt}
+%\DimCaseTF{2\lTmpaDim}{
+% {5pt} {\Result{Small}}
+% {4pt+6pt} {\Result{Medium}}
+% {-10pt} {\Result{Negative}}
+%}{
+% \Result{[Some Match]}
+%}{
+% \Result{[No Match]}
+%}
+%\IgnoreSpacesOff
+%\end{demohigh}
+\end{function}
+
+\chapter{Comma Separated Lists (\texttt{Clist})}
+
+\section{Constant and Scratch Comma Lists}
+
+\begin{variable}{\cEmptyClist}
+Constant that is always empty.
+\end{variable}
+
+\begin{variable}{\lTmpaClist,\lTmpbClist,\lTmpcClist,\lTmpiClist,\lTmpjClist,\lTmpkClist}
+Scratch comma lists for local assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\begin{variable}{\gTmpaClist,\gTmpbClist,\gTmpcClist,\gTmpiClist,\gTmpjClist,\gTmpkClist}
+Scratch comma lists for global assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\section{Creating and Using Comma Lists}
+
+\begin{function}{\ClistNew}
+\begin{syntax}
+\cs{ClistNew} \meta{comma list}
+\end{syntax}
+Creates a new \meta{comma list} or raises an error if the name is
+already taken. The declaration is global. The \meta{comma list}
+initially contains no items.
+\end{function}
+
+\begin{function}{\ClistConst}
+\begin{syntax}
+\cs{ClistConst} \meta{clist var} \Arg{comma list}
+\end{syntax}
+Creates a new constant \meta{clist var} or raises an error
+if the name is already taken. The value of the
+\meta{clist var} is set globally to the
+\meta{comma list}.
+\end{function}
+
+\begin{function}{\ClistVarJoin}
+\begin{syntax}
+\cs{ClistVarJoin} \meta{clist var} \Arg{separator}
+\end{syntax}
+Returns the contents of the \meta{clist var},
+with the \meta{separator} between the items.
+%If the comma list has a single item, it is placed in the input stream,
+%and a comma list with no items produces no output.
+%An error is raised if the variable does not exist or if it is invalid.
+For example,
+\begin{demohigh}
+\ClistSet \lTmpaClist { a , b , , c , {de} , f }
+\ClistVarJoin \lTmpaClist { and }
+\end{demohigh}
+%\begin{texnote}
+%The result is returned within the \tn{unexpanded}
+%primitive (\cs{exp_not:n}), which means that the \meta{items}
+%do not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\ClistVarJoinExtended}
+\begin{syntax}
+\cs{ClistVarJoinExtended} \meta{clist var} \Arg{separator between two} \Arg{separator between more than two} \Arg{separator between final two}
+\end{syntax}
+Returns the contents of the \meta{clist var},
+with the appropriate \meta{separator} between the items. Namely, if
+the comma list has more than two items, the \meta{separator between
+more than two} is placed between each pair of items except the
+last, for which the \meta{separator between final two} is used. If
+the comma list has exactly two items, then they are joined with
+the \meta{separator between two} and returns.
+%If the comma list has a single item, it is placed in the input stream,
+%and a comma list with no items produces no output.
+%An error is raised if the variable does not exist or if it is invalid.
+For example,
+\begin{demohigh}
+\ClistSet \lTmpaClist { a , b , , c , {de} , f }
+\ClistVarJoinExtended \lTmpaClist { and } {, } {, and }
+\end{demohigh}
+The first separator argument is not used in this case
+because the comma list has more than $2$ items.
+%\begin{texnote}
+%The result is returned within the \tn{unexpanded}
+%primitive (\cs{exp_not:n}), which means that the \meta{items}
+%do not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\ClistJoin,\ClistJoinExtended}
+\begin{syntax}
+\cs{ClistJoin} \meta{comma list} \Arg{separator}
+\cs{ClistJoinExtended} \meta{comma list} \Arg{separator between two} \Arg{separator between more than two} \Arg{separator between final two}
+\end{syntax}
+Returns the contents of the \meta{comma list},
+with the appropriate \meta{separator} between the items. As for
+\cs{ClistSet}, blank items are omitted, spaces are removed from
+both sides of each item, then a set of braces is removed if the
+resulting space-trimmed item is braced. The \meta{separators} are
+then inserted in the same way as for \cs{ClistVarJoin} and
+\cs{ClistVarJoinExtended}, respectively.
+%\begin{texnote}
+%The result is returned within the \tn{unexpanded}
+%primitive (\cs{exp_not:n}), which means that the \meta{items}
+%do not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\section{Viewing Comma Lists}
+
+\begin{function}{\ClistLog}
+\begin{syntax}
+\cs{ClistLog} \Arg{tokens}
+\end{syntax}
+Writes the entries in the comma list in the log file. See also
+\cs{ClistShow} which displays the result in the terminal.
+\end{function}
+
+\begin{function}{\ClistVarLog}
+\begin{syntax}
+\cs{ClistVarLog} \meta{comma list}
+\end{syntax}
+Writes the entries in the \meta{comma list} in the log file. See
+also \cs{ClistVarShow} which displays the result in the terminal.
+\end{function}
+
+\begin{function}{\ClistShow}
+\begin{syntax}
+\cs{ClistShow} \Arg{tokens}
+\end{syntax}
+Displays the entries in the comma list in the terminal.
+\end{function}
+
+\begin{function}{\ClistVarShow}
+\begin{syntax}
+\cs{ClistVarShow} \meta{comma list}
+\end{syntax}
+Displays the entries in the \meta{comma list} in the terminal.
+\end{function}
+
+\section{Setting Comma Lists}
+
+\begin{function}{\ClistSet}
+\begin{syntax}
+\cs{ClistSet} \meta{comma list} \verb|{|\meta{item_1},\ldots{},\meta{item_n}\verb|}|
+\end{syntax}
+Sets \meta{comma list} to contain the \meta{items},
+removing any previous content from the variable.
+Blank items are omitted, spaces are removed from both sides of each
+item, then a set of braces is removed if the resulting space-trimmed
+item is braced.
+To store some \meta{tokens} as a single \meta{item} even if the
+\meta{tokens} contain commas or spaces, add a set of braces:
+\cs{ClistSet} \meta{comma list} \verb|{| \Arg{tokens} \verb|}|.
+\end{function}
+
+\begin{function}{\ClistSetEq}
+\begin{syntax}
+\cs{ClistSetEq} \meta{comma list_1} \meta{comma list_2}
+\end{syntax}
+Sets the content of \meta{comma list_1} equal to that of
+\meta{comma list_2}. To set a token list variable equal to a comma
+list variable, use \cs{TlSetEq}. Conversely, setting a comma
+list variable to a token list is unadvisable unless one checks
+space-trimming and related issues.
+\end{function}
+
+%\begin{function}{\ClistSetFromSeq}
+%\begin{syntax}
+%\cs{ClistSetFromSeq} \meta{comma list} \meta{sequence}
+%\end{syntax}
+%Converts the data in the \meta{sequence} into a \meta{comma list}:
+%the original \meta{sequence} is unchanged.
+%Items which contain either spaces or commas are surrounded by braces.
+%\end{function}
+
+\begin{function}{\ClistClear}
+\begin{syntax}
+\cs{ClistClear} \meta{comma list}
+\end{syntax}
+Clears all items from the \meta{comma list}.
+\end{function}
+
+\begin{function}{\ClistClearNew}
+\begin{syntax}
+\cs{ClistClearNew} \meta{comma list}
+\end{syntax}
+Ensures that the \meta{comma list} exists globally by applying
+\cs{ClistNew} if necessary, then applies \cs{ClistClear} to leave
+the list empty.
+\end{function}
+
+\begin{function}{\ClistConcat}
+\begin{syntax}
+\cs{ClistConcat} \meta{comma list_1} \meta{comma list_2} \meta{comma list_3}
+\end{syntax}
+Concatenates the content of \meta{comma list_2} and \meta{comma list_3}
+together and saves the result in \meta{comma list_1}. The items in
+\meta{comma list_2} are placed at the left side of the new comma list.
+\end{function}
+
+\begin{function}{\ClistPutLeft}
+\begin{syntax}
+\cs{ClistPutLeft} \meta{comma list} \verb|{|\meta{item_1},\ldots{},\meta{item_n}\verb|}|
+\end{syntax}
+Appends the \meta{items} to the left of the \meta{comma list}.
+Blank items are omitted, spaces are removed from both sides of each
+item, then a set of braces is removed if the resulting space-trimmed
+item is braced.
+To append some \meta{tokens} as a single \meta{item} even if the
+\meta{tokens} contain commas or spaces, add a set of braces:
+\cs{ClistPutLeft} \meta{comma list} \verb|{| \Arg{tokens} \verb|}|.
+\end{function}
+
+\begin{function}{\ClistPutRight}
+\begin{syntax}
+\cs{ClistPutRight} \meta{comma list} \verb|{|\meta{item_1},\ldots{},\meta{item_n}\verb|}|
+\end{syntax}
+Appends the \meta{items} to the right of the \meta{comma list}.
+Blank items are omitted, spaces are removed from both sides of each
+item, then a set of braces is removed if the resulting space-trimmed
+item is braced.
+To append some \meta{tokens} as a single \meta{item} even if the
+\meta{tokens} contain commas or spaces, add a set of braces:
+\cs{ClistPutRight} \meta{comma list} \verb|{| \Arg{tokens} \verb|}|.
+\end{function}
+
+\section{Modifying Comma Lists}
+
+While comma lists are normally used as ordered lists, it may be
+necessary to modify the content. The functions here may be used
+to update comma lists, while retaining the order of the unaffected
+entries.
+
+\begin{function}{\ClistRemoveDuplicates}
+\begin{syntax}
+\cs{ClistRemoveDuplicates} \meta{comma list}
+\end{syntax}
+Removes duplicate items from the \meta{comma list}, leaving the
+left most copy of each item in the \meta{comma list}. The \meta{item}
+comparison takes place on a token basis, as for \cs{TlIfEqTF}.
+\begin{texnote}
+This function iterates through every item in the \meta{comma list} and
+does a comparison with the \meta{items} already checked. It is therefore
+relatively slow with large comma lists.
+Furthermore, it may fail if any of the items in the
+\meta{comma list} contains \verb|{|, \verb|}|, or \verb|#|
+(assuming the usual \TeX{} category codes apply).
+\end{texnote}
+\end{function}
+
+\begin{function}{\ClistRemoveAll}
+\begin{syntax}
+\cs{ClistRemoveAll} \meta{comma list} \Arg{item}
+\end{syntax}
+Removes every occurrence of \meta{item} from the \meta{comma list}.
+The \meta{item} comparison takes place on a token basis, as for
+\cs{TlIfEqTF}.
+\begin{texnote}
+The function may fail if the \meta{item} contains \verb|{|, \verb|}|, or \verb|#|
+(assuming the usual \TeX{} category codes apply).
+\end{texnote}
+\end{function}
+
+\begin{function}{\ClistReverse}
+\begin{syntax}
+\cs{ClistReverse} \meta{comma list}
+\end{syntax}
+Reverses the order of items stored in the \meta{comma list}.
+\end{function}
+
+%\begin{function}{\ClistSort}
+%\begin{syntax}
+%\cs{ClistSort} \meta{clist var} \Arg{comparison code}
+%\end{syntax}
+%Sorts the items in the \meta{clist var} according to the
+%\meta{comparison code}, and assigns the result to
+%\meta{clist var}. The details of sorting comparison are
+%described in Section \ref{sec:l3sort:mech}.
+%\end{function}
+
+\section{Working with the Contents of Comma Lists}
+
+\begin{function}{\ClistCount,\ClistVarCount}
+\begin{syntax}
+\cs{ClistCount} \Arg{comma list}
+\cs{ClistVarCount} \meta{comma list}
+\end{syntax}
+Returns the number of items in the \meta{comma list}
+as an \meta{integer denotation}. The total number of items
+in a \meta{comma list} includes those which are duplicates,
+\emph{i.e.} every item in a \meta{comma list} is counted.
+\end{function}
+
+\begin{function}{\ClistItem}
+\begin{syntax}
+\cs{ClistItem} \Arg{comma list} \Arg{integer expression}
+\end{syntax}
+Indexing items in the \meta{comma list} from $1$ at the top (left), this
+function evaluates the \meta{integer expression} and returns the
+appropriate item from the comma list. If the
+\meta{integer expression} is negative, indexing occurs from the
+bottom (right) of the comma list. When the \meta{integer expression}
+is larger than the number of items in the \meta{comma list} (as
+calculated by \cs{ClistCount}) then the function returns nothing.
+%\begin{texnote}
+%The result is returned within the \tn{unexpanded}
+%primitive (\cs{exp_not:n}), which means that the \meta{item}
+%does not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\ClistVarItem}
+\begin{syntax}
+\cs{ClistVarItem} \meta{comma list} \Arg{integer expression}
+\end{syntax}
+Indexing items in the \meta{comma list} from $1$ at the top (left), this
+function evaluates the \meta{integer expression} and returns the
+appropriate item from the comma list. If the
+\meta{integer expression} is negative, indexing occurs from the
+bottom (right) of the comma list. When the \meta{integer expression}
+is larger than the number of items in the \meta{comma list} (as
+calculated by \cs{ClistVarCount}) then the function returns nothing.
+%\begin{texnote}
+%The result is returned within the \tn{unexpanded}
+%primitive (\cs{exp_not:n}), which means that the \meta{item}
+%does not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\ClistRandItem,\ClistVarRandItem}
+\begin{syntax}
+\cs{ClistRandItem} \Arg{comma list}
+\cs{ClistVarRandItem} \meta{clist var}
+\end{syntax}
+Selects a pseudo-random item of the \meta{comma list}.
+If the \meta{comma list} has no item, the result is empty.
+%\begin{texnote}
+%The result is returned within the \tn{unexpanded}
+%primitive (\cs{exp_not:n}), which means that the \meta{item}
+%does not expand further when appearing in an \texttt{x}-type
+%or \texttt{e}-type argument expansion.
+%\end{texnote}
+\end{function}
+
+\section{Comma Lists as Stacks}
+
+Comma lists can be used as stacks, where data is pushed to and popped
+from the top of the comma list. (The left of a comma list is the top, for
+performance reasons.) The stack functions for comma lists are not
+intended to be mixed with the general ordered data functions detailed
+in the previous section: a comma list should either be used as an
+ordered data type or as a stack, but not in both ways.
+
+\begin{function}{\ClistGet,\ClistGetTF}
+\begin{syntax}
+\cs{ClistGet} \meta{comma list} \meta{token list variable}
+\cs{ClistGetT} \meta{comma list} \meta{token list variable} \meta{true code}
+\cs{ClistGetF} \meta{comma list} \meta{token list variable} \meta{false code}
+\cs{ClistGetTF} \meta{comma list} \meta{token list variable} \meta{true code} \meta{false code}
+\end{syntax}
+Stores the left-most item from a \meta{comma list} in the
+\meta{token list variable} without removing it from the
+\meta{comma list}. The \meta{token list variable} is assigned locally.
+%In the non-branching version, if the \meta{comma list} is empty the
+%\meta{token list variable} is set to the marker value \cs{qNoValue}.
+\end{function}
+
+\begin{function}{\ClistPop,\ClistPopT,\ClistPopF,\ClistPopTF}
+\begin{syntax}
+\cs{ClistPop} \meta{comma list} \meta{token list variable}
+\cs{ClistPopT} \meta{comma list} \meta{token list variable} \Arg{true code}
+\cs{ClistPopF} \meta{comma list} \meta{token list variable} \Arg{false code}
+\cs{ClistPopTF} \meta{comma list} \meta{token list variable} \Arg{true code} \Arg{false code}
+\end{syntax}
+Pops the left-most item from a \meta{comma list} into the
+\meta{token list variable}, \emph{i.e.} removes the item from the
+comma list and stores it in the \meta{token list variable}.
+The assignment of the \meta{token list variable} is local.
+If the \meta{comma list} is empty,
+the value of the \meta{token list variable} is
+not defined in this case and should not be relied upon.
+\end{function}
+
+\begin{function}{\ClistPush}
+\begin{syntax}
+\cs{ClistPush} \meta{comma list} \Arg{items}
+\end{syntax}
+Adds the \Arg{items} to the top of the \meta{comma list}.
+Spaces are removed from both sides of each item as for any
+\texttt{n}-type comma list.
+\end{function}
+
+\section{Mapping over Comma Lists}
+
+%The functions described in this section apply a specified function
+%to each item of a comma list.
+%All mappings are done at the current group level, \emph{i.e.} any
+%local assignments made by the \meta{function} or \meta{code} discussed
+%below remain in effect after the loop.
+
+When the comma list is given explicitly, %as an \texttt{n}-type argument,
+spaces are trimmed around each item.
+If the result of trimming spaces is empty, the item is ignored.
+Otherwise, if the item is surrounded by braces, one set is removed,
+and the result is passed to the mapped function. Thus, if the
+comma list that is being mapped is \verb*|{a , {{b} }, ,{}, {c},}|
+then the arguments passed to the mapped function are
+`\verb*|a|', `\verb*|{b} |', an empty argument, and `\verb*|c|'.
+
+When the comma list is given as a variable, spaces
+have already been trimmed on input, and items are simply stripped
+of one set of braces if any. This case is more efficient than using
+explicit comma lists.
+
+%\begin{function}{\ClistMapFunction,\ClistVarMapFunction}
+%\begin{syntax}
+%\cs{ClistMapFunction} \Arg{comma list} \meta{function}
+%\cs{ClistVarMapFunction} \meta{comma list} \meta{function}
+%\end{syntax}
+%Applies \meta{function} to every \meta{item} stored in the
+%\meta{comma list}. The \meta{function} receives one argument for
+%each iteration. The \meta{items} are returned from left to right.
+%The function \cs{ClistMapInline} is in general more efficient
+%than \cs{ClistMapFunction}.
+%\end{function}
+
+\begin{function}{\ClistMapInline,\ClistVarMapInline}
+\begin{syntax}
+\cs{ClistMapInline} \Arg{comma list} \Arg{inline function}
+\cs{ClistVarMapInline} \meta{comma list} \Arg{inline function}
+\end{syntax}
+Applies \meta{inline function} to every \meta{item} stored
+within the \meta{comma list}. The \meta{inline function} should
+consist of code which receives the \meta{item} as \verb|#1|.
+The \meta{items} are returned from left to right.
+For example
+\begin{codehigh}
+\IgnoreSpacesOn
+\TlClear \lTmpaTl
+\ClistMapInline {one,two,three} {
+ \TlPutRight \lTmpaTl {(#1)}
+}
+\Result {\TlUse\lTmpaTl}
+\IgnoreSpacesOff
+\end{codehigh}
+produces (one)(two)(three).
+\end{function}
+
+\begin{function}{\ClistMapVariable,\ClistVarMapVariable}
+\begin{syntax}
+\cs{ClistMapVariable} \Arg{comma list} \meta{variable} \Arg{code}
+\cs{ClistVarMapVariable} \meta{comma list} \meta{variable} \Arg{code}
+\end{syntax}
+Stores each \meta{item} of the \meta{comma list} in turn in the
+(token list) \meta{variable} and applies the \meta{code}. The
+\meta{code} will usually make use of the \meta{variable}, but this
+is not enforced. The assignments to the \meta{variable} are local.
+Its value after the loop is the last \meta{item} in the \meta{comma
+list}, or its original value if there were no \meta{item}. The
+\meta{items} are returned from left to right.
+\end{function}
+
+%\begin{function}{\ClistMapTokens,\ClistVarMapTokens}
+%\begin{syntax}
+%\cs{ClistMapTokens} \Arg{comma list} \Arg{code}
+%\cs{ClistVarMapTokens} \meta{clist var} \Arg{code}
+%\end{syntax}
+%Calls \meta{code} \Arg{item} for every \meta{item} stored in the
+%\meta{comma list}. The \meta{code} receives each \meta{item} as a
+%trailing brace group. If the \meta{code} consists of a single
+%function this is equivalent to \cs{ClistMapFunction} or \cs{ClistVarMapFunction}.
+%\end{function}
+
+%\begin{function}{\ClistMapBreak}
+%\begin{syntax}
+%\cs{ClistMapBreak}
+%\end{syntax}
+%Used to terminate a clist map function before all
+%entries in the \meta{comma list} have been processed. This
+%normally takes place within a conditional statement, for example
+%\begin{verbatim}
+%\clist_map_inline:Nn \l_my_clist
+%{
+%\str_if_eq:nnTF { #1 } { bingo }
+%{ \clist_map_break: }
+%{
+%Do something useful
+%}
+%}
+%\end{verbatim}
+%Use outside of a clist map scenario leads to low
+%level \TeX{} errors.
+%\begin{texnote}
+%When the mapping is broken, additional tokens may be inserted
+%before further items are taken
+%from the input stream. This depends on the design of the mapping
+%function.
+%\end{texnote}
+%\end{function}
+%
+%\begin{function}{\ClistMapBreakDo}
+%\begin{syntax}
+%\cs{ClistMapBreakDo} \Arg{code}
+%\end{syntax}
+%Used to terminate a clist map function before all
+%entries in the \meta{comma list} have been processed, inserting
+%the \meta{code} after the mapping has ended. This
+%normally takes place within a conditional statement, for example
+%\begin{verbatim}
+%\clist_map_inline:Nn \l_my_clist
+%{
+%\str_if_eq:nnTF { #1 } { bingo }
+%{ \clist_map_break:n { <code> } }
+%{
+%Do something useful
+%}
+%}
+%\end{verbatim}
+%Use outside of a clist map scenario leads to low
+%level \TeX{} errors.
+%\begin{texnote}
+%When the mapping is broken, additional tokens may be inserted
+%before the \meta{code} is
+%inserted into the input stream.
+%This depends on the design of the mapping function.
+%\end{texnote}
+%\end{function}
+
+\section{Comma List Conditionals}
+
+\begin{function}{\ClistIfExist,\ClistIfExistTF}
+\begin{syntax}
+\cs{ClistIfExist} \meta{comma list}
+\cs{ClistIfExistTF} \meta{comma list} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests whether the \meta{comma list} is currently defined. This does
+not check that the \meta{comma list} really is a comma list.
+\end{function}
+
+\begin{function}{\ClistIfEmpty,\ClistIfEmptyTF}
+\begin{syntax}
+\cs{ClistIfEmpty} \Arg{comma list}
+\cs{ClistIfEmptyTF} \Arg{comma list} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the \meta{comma list} is empty (containing no items).
+The rules for space trimming are as for other \texttt{n}-type
+comma-list functions, hence the comma list \verb|{ , ,, }| (without
+outer braces) is empty, while \verb|{ ,{},}| (without outer braces)
+contains one element, which happens to be empty: the comma-list
+is not empty.
+\end{function}
+
+\begin{function}{\ClistVarIfEmpty,\ClistVarIfEmptyTF}
+\begin{syntax}
+\cs{ClistVarIfEmpty} \meta{comma list}
+\cs{ClistVarIfEmptyTF} \meta{comma list} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the \meta{comma list} is empty (containing no items).
+\end{function}
+
+\begin{function}{\ClistIfIn,\ClistIfInTF}
+\begin{syntax}
+\cs{ClistIfIn} \Arg{comma list} \Arg{item}
+\cs{ClistIfInTF} \Arg{comma list} \Arg{item} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the \meta{item} is present in the \meta{comma list}.
+In the case of an \texttt{n}-type \meta{comma list}, the usual rules
+of space trimming and brace stripping apply. For example
+\begin{demohigh}
+\ClistIfInTF { a , {b} , {b} , c } {b} {Yes} {No}
+\end{demohigh}
+%\begin{texnote}
+%The function may fail if the \meta{item} contains \verb|{|, \verb|}|, or \verb|#|
+%(assuming the usual \TeX{} category codes apply).
+%\end{texnote}
+\end{function}
+
+\begin{function}{\ClistVarIfIn,\ClistVarIfInTF}
+\begin{syntax}
+\cs{ClistVarIfIn} \meta{comma list} \Arg{item}
+\cs{ClistVarIfInTF} \meta{comma list} \Arg{item} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the \meta{item} is present in the \meta{comma list}.
+In the case of an \texttt{n}-type \meta{comma list}, the usual rules
+of space trimming and brace stripping apply.
+%\begin{texnote}
+%The function may fail if the \meta{item} contains \verb|{|, \verb|}|, or \verb|#|
+%(assuming the usual \TeX{} category codes apply).
+%\end{texnote}
+\end{function}
+
\chapter{The Source Code}
%\CodeHigh{lite}
@@ -991,4 +4363,3 @@ For example
\dochighinput[language=latex/latex3]{functional.sty}
\end{document}
-
diff --git a/macros/latex/contrib/thuthesis/CHANGELOG.md b/macros/latex/contrib/thuthesis/CHANGELOG.md
index d68be6a460..086fa411a5 100644
--- a/macros/latex/contrib/thuthesis/CHANGELOG.md
+++ b/macros/latex/contrib/thuthesis/CHANGELOG.md
@@ -6,67 +6,110 @@
## [Unreleased]
+## [v7.2.4] - 2022-03-19
+
+### Added
+
+- 增加警告提醒本科生将附录置于声明后([#682](https://github.com/tuna/thuthesis/issues/682))。
+- 增加警告提醒本科生将插图索引和表格索引置于正文后。
+- 本科生的 `\listoffiguresandtables` 改为分开的插图索引和表格索引。
+
+### Changed
+
+- 本科生的“答辩委员会名单”、“指导教师/小组学术评语”和“答辩委员会决议书”改为不输出内容([#688](https://github.com/tuna/thuthesis/issues/688))。
+- 研究生和博后不再默认载入 `bibunits`([#710](https://github.com/tuna/thuthesis/issues/710))。
+- 参考文献表中预印本的文献类型标识改为“A”。
+- 允许多行页眉([#735](https://github.com/tuna/thuthesis/issues/735))。
+
+### Fixed
+
+- 修复本科生“使用授权说明”中“日期”后缺失的冒号([#679](https://github.com/tuna/thuthesis/issues/679))。
+- 修复 `TikZ` 的 `external` 库与 `pdfpages` 的兼容性问题([#693](https://github.com/tuna/thuthesis/issues/693))。
+- 参考文献表中专利文献使用 `address`/`lcoation` 输出专利国别。
+- 修正一章内脚注数量超过 10 个时的报错问题,改为警告([#742](https://github.com/tuna/thuthesis/issues/742))。
+
+### Removed
+
+- 去掉了 `siunitx` 的 `inter-unit-product` 设置。
+
## [v7.2.3] - 2021-05-31
+
### Changed
-- 中文模板的公式编号改为中文括号(#297)。
+
+- 中文模板的公式编号改为中文括号([#287](https://github.com/tuna/thuthesis/issues/287))。
### Fixed
-- 修正硕士论文书脊的字号(#647)。
-- 修正本科生附录(调研和翻译)的目录在 TeX Live 2019 前无法生成的问题(#659)。
-- 修正本科生主要符号表的标题(#661)。
+
+- 修正硕士论文书脊的字号([#647](https://github.com/tuna/thuthesis/issues/647))。
+- 修正本科生附录(调研和翻译)的目录在 TeX Live 2019 前无法生成的问题([#659](https://github.com/tuna/thuthesis/issues/659))。
+- 修正本科生主要符号表的标题([#661](https://github.com/tuna/thuthesis/issues/661))。
## [v7.2.2] - 2021-04-03
+
### Changed
-- 修改授权说明的内容和格式,同 2020 年 12 月版 Word 模板一致(#625)。
-- 参考文献的页码前与冒号之间加上空格,同步 2021 年 3 月版《指南》的格式修改(#629)。
+
+- 修改授权说明的内容和格式,同 2020 年 12 月版 Word 模板一致([#625](https://github.com/tuna/thuthesis/issues/625))。
+- 参考文献的页码前与冒号之间加上空格,同步 2021 年 3 月版《指南》的格式修改([#629](https://github.com/tuna/thuthesis/issues/629))。
- 著者-出版年制参考文献表的著者姓名与年份之间改为逗号。
### Fixed
-- 修正图表等浮动体与文字之间的距离(#614、#617)。
-- 修正表格、算法等浮动体的行距(#619)。
-- 修正了上标式引用后与中文之间多余的空格(#624)。
-- 修正了参考文献的姓名或年份中含有中括号时的引用错误(#630)。
+
+- 修正图表等浮动体与文字之间的距离([#614](https://github.com/tuna/thuthesis/issues/614)、[#617](https://github.com/tuna/thuthesis/issues/617))。
+- 修正表格、算法等浮动体的行距([#619](https://github.com/tuna/thuthesis/issues/619))。
+- 修正了上标式引用后与中文之间多余的空格([#624](https://github.com/tuna/thuthesis/issues/624))。
+- 修正了参考文献的姓名或年份中含有中括号时的引用错误([#630](https://github.com/tuna/thuthesis/issues/630))。
## [v7.2.1] - 2021-03-21
+
### Added
+
- 在文档中添加更多关于数学公式样式的说明。
### Changed
+
- 允许控制研究生的声明页是否添加页眉页脚。
### Fixed
-- 调整文字与图表等浮动体之间的距离(#614)。
+
+- 调整文字与图表等浮动体之间的距离([#614](https://github.com/tuna/thuthesis/issues/614))。
- 修复一些字体选择相关的问题。
## [v7.2.0] - 2021-03-12
+
### Added
+
- 新增英文版写作指南要求的格式。
-- 新增选题报告的格式(#579)。
+- 新增选题报告的格式([#579](https://github.com/tuna/thuthesis/issues/579))。
- 新增 `figure-number-sepatator` 等选项设置图表编号的连接符。
- 新增数学符号字体风格选项 `math-style`。
- 新增选项控制数学字体风格的细节:`uppercase-greek`、`less-than-or-equal`、`integral`、`integral-limits`、`partial` 和 `math-ellipsis`。
- 新增数学字体试验性选项 `math-font = newtx`。
### Changed
-- 研究生的声明页默认加上页眉和页码,不受 `page-style` 的控制(#574)。
-- 取消图表标题的悬挂缩进(#589)。
+
+- 研究生的声明页默认加上页眉和页码,不受 `page-style` 的控制([#574](https://github.com/tuna/thuthesis/issues/574))。
+- 取消图表标题的悬挂缩进([#589](https://github.com/tuna/thuthesis/issues/589))。
- 英文封面的联合导师改为“Co-supervisor”。
- 联合导师的 key 改为 `co-supervisor`,同英文版模板一致。
### Fixed
-- 修正 `longtable` 宏包的配置(#584)。
-- 修正本科生的“目录”、“声明”和“致谢”等标题中的空白(#591)。
+
+- 修正 `longtable` 宏包的配置([#584](https://github.com/tuna/thuthesis/issues/584))。
+- 修正本科生的“目录”、“声明”和“致谢”等标题中的空白([#591](https://github.com/tuna/thuthesis/issues/591))。
- 修正参考文献的格式,取消页码与前面冒号之间的空格。
- 修正中文封面的字距。
## [v7.1.0] - 2020-10-14
+
### Changed
+
- 更新摘要的标题格式(研究生 2020-09-18 版)。
- 更新目录的格式(研究生 2020-09-18 版)。
- 图表浮动体的位置参数默认为 `h`。
- 更新示例文档。
### Fixed
+
- 修正 “keywords” 的拼写。
- 修正授权使用说明的内容。
- 修正授伪粗字体的粗度。
@@ -78,17 +121,21 @@
- 修正脚注的行距和缩进距离。
## [v7.0.0] - 2020-09-09
+
### Changed
+
- 更新 2020 年版目录、插图和附表清单的格式。
- 更新 2020 年版使用授权说明的内容。
- 更新 2020 年版参考文献表的格式。
### Added
+
- 新增 2020 年版“答辩委员会名单”页。
- 新增 biblatex 支持。
- 新增本科生外文系格式的支持。
### Fixed
+
- 修正本科生密级的字体。
- 修正表格的默认字号。
- 修正参考文献表的行距和段前段后间距。
@@ -97,72 +144,88 @@
- 修正封面的语言切换。
## [v6.1.3] - 2020-07-09
+
### Added
+
- 新增选项 `statement-page-style = empty / plain` 同时控制声明的页眉和页脚。
### Fixed
+
- `\record` 命令中,如果 `output` 配置为 `print`,则强制进行 `\cleardoublepage`,保证记录表独立成页。
-- 修正了在导言区设置论文主要语言无效的问题(#560)。
+- 修正了在导言区设置论文主要语言无效的问题([#560](https://github.com/tuna/thuthesis/issues/560))。
- 修正了研究生插入扫描版声明页时的页眉。
### Deprecated
+
- 选项 `statement-page-number` 已过时。
## [v6.1.2] - 2020-06-14
+
### Changed
+
- `\statement` 和 `\copyrightpage` 命令都会在 PDF 中生成相应位置的书签。
- `\statement` 命令编译生成声明页默认不含页码。
- `\statement[xxx.pdf]` 插入扫描页时在页脚生成页码,以解决打印版与电子版页码不一致的情况。
- 使用 `l3build` 编译的版本,在提交到 CTAN 时提供 TDS 结构,以解决编译时 `tsinghua-name-bachelor.pdf` 找不到的问题。
### Added
+
- 添加 `\record` 命令用于本科生插入综合论文训练记录表,同时在 PDF 中生成对应书签。
- 添加选项 `statement-page-number` 控制编译声明页时是否含页码。
### Fixed
+
- 修正示例代码中关于 `\statement` 的 typo。
## [v6.1.1] - 2020-06-12
+
### Changed
+
- 书脊中的西文不再需要调整高度。
- 修改预生成的隶书版本本科生封面学校名称的文件名为 `tsinghua-name-bachelor.pdf`,不再尝试使用系统字体生成。
- 将论文示例的文件名更改为 `thuthesis-example.tex / pdf`,以符合 CTAN 的要求。
### Added
-- 添加选项 `include-spine`,允许在正文中插入书脊页(#551)。
+
+- 添加选项 `include-spine`,允许在正文中插入书脊页([#551](https://github.com/tuna/thuthesis/issues/551))。
- 添加选项 `spine-title`、`spine-author` 控制书脊的内容。
- 添加选项 `spine-font` 控制书脊的字号。
-- 添加选项 `output` 选择输出格式为打印版或用于提交的电子版(#553)。
+- 添加选项 `output` 选择输出格式为打印版或用于提交的电子版([#553](https://github.com/tuna/thuthesis/issues/553))。
### Fixed
+
- 修正书脊的格式。
- 修复文档中 Changelog 的格式问题。
## [v6.1.0] - 2020-06-08
+
### Changed
+
- 在 `translation` 环境中使用 `\bibliography` 改为生成参考文献,
- 对应的原文索引改为 `translation-index` 环境(#529)。
+ 对应的原文索引改为 `translation-index` 环境([#529](https://github.com/tuna/thuthesis/issues/529))。
- 附录的图、表不再加入索引。
- 使用 `threeparttable` 示例表内脚注。
-- 本科生的目录章标题的西文字母和数字默认使用 Arial(#542)。
+- 本科生的目录章标题的西文字母和数字默认使用 Arial([#542](https://github.com/tuna/thuthesis/issues/542))。
- GitHub repo 所有者更改为清华大学 TUNA 协会。
-- 接管 `ctex` 的 `fontset` 选项,允许更灵活的字体配置(#498)。
+- 接管 `ctex` 的 `fontset` 选项,允许更灵活的字体配置([#498](https://github.com/tuna/thuthesis/issues/498))。
### Fixed
-- 本科生附录的调研报告使用英文(#479)。
+
+- 本科生附录的调研报告使用英文([#479](https://github.com/tuna/thuthesis/issues/479))。
- 修正本科生附录的 `algorithm` 和 `listings` 环境的编号格式。
-- 研究生的“使用授权说明”增加一空白页(#504)。
-- 修正 publication 列表行距问题(#507)。
+- 研究生的“使用授权说明”增加一空白页([#504](https://github.com/tuna/thuthesis/issues/504))。
+- 修正 publication 列表行距问题([#507](https://github.com/tuna/thuthesis/issues/507))。
- 修正研究生目录的行距。
-- 调整本科生封面有辅导教师、联合指导教师时的格式(#522, #537)。
-- 修正本科生封面日期的字体(#532)。
+- 调整本科生封面有辅导教师、联合指导教师时的格式([#522](https://github.com/tuna/thuthesis/issues/522), [#537](https://github.com/tuna/thuthesis/issues/537))。
+- 修正本科生封面日期的字体([#532](https://github.com/tuna/thuthesis/issues/532))。
- 设置三线表横线的默认粗度。
- 修正文档中关于本科生学科(专业)名称的说明。
- 允许用户使用文档类选项 `openright`。
-- 修正本科生的“单设一页”格式(#545)。
+- 修正本科生的“单设一页”格式([#545](https://github.com/tuna/thuthesis/issues/545))。
- 研究生的正文(main matter)起始于奇数页。
### Added
+
- 允许使用边注。
- 新增 `amsthm` 支持。
- 支持单个关键词设置样式。
@@ -170,37 +233,47 @@
- 添加选项 `toc-chapter-style` 控制本科生的目录章标题的西文字体。
## [v6.0.2] - 2020-02-23
+
### Fixed
-- 修复图表公式目录内容缺失(#467)。
+
+- 修复图表公式目录内容缺失([#467](https://github.com/tuna/thuthesis/issues/467))。
- 修复 Github Actions 执行 l3build check 问题。
- 文本模式使用 `\checkmark`。
### Added
+
- 补充 PDF 元信息:文档标题,语言。
### Changed
+
- 补充“著者-出版年”引用命令使用方法。
- 使用 `xeCJKfntef` 替换 `CJKfntef`。
## [v6.0.1] - 2020-02-03
+
### Changed
+
- 更新文档。
- 更新 bib 测试用例。
### Fixed
-- 修复 PDF 目录层级问题(#457)。
-- 修复 PDF 中章节连接问题(#453)。
+
+- 修复 PDF 目录层级问题([#457](https://github.com/tuna/thuthesis/issues/457))。
+- 修复 PDF 中章节连接问题([#453](https://github.com/tuna/thuthesis/issues/453))。
## [v6.0.0] - 2020-01-06
+
### Added
+
- 新增 `survey`(调研阅读报告)和 `translation`(书面翻译)环境用于本科生的附录,
- 其中的参考文献引用独立于论文正文(#343)。
+ 其中的参考文献引用独立于论文正文([#343](https://github.com/tuna/thuthesis/issues/343))。
- 新增论文语言选项。
- 增加 `l3build` 测试。
### Changed
+
- 重新设计 `\thusetup` 的接口。
-- 指导教师的姓名和职称用英文逗号分开(#424)。
+- 指导教师的姓名和职称用英文逗号分开([#424](https://github.com/tuna/thuthesis/issues/424))。
- 重新设计封面(题名页)。
- `\makecover` 拆分为 `\maketitle`、`\copyrightpage`。
- 中英文摘分别用 `abstract`、`abstract*` 环境生成。
@@ -212,26 +285,34 @@
- 整理 Makefile,便于日常使用。
## Removed
+
- 移除 `secret` 选项。
- 移除 `translationbib` 环境。
- 移除 `tocarialchapter`、`tocarialchapterentry` 和 `tocarialchapterpage` 选项。
- 只保留 xelatex 编译方式。
### Fixed
+
- 修正本科生的文献引用样式。
- 修正本科生目录章标题的字体。
- 处理 `hyperref` 与 `unicode-math` 的兼容性问题。
## [v5.5.2] - 2019-04-21
+
### Changed
+
- 使用 XITS 数学字体。
## [v5.5.1] - 2019-04-16
+
### Changed
+
- `\thu@textcircled`: 修复 minipage 中 footnote 编号问题。
## [v5.5.0] - 2019-03-15
+
### Changed
+
- 增加选项使用英文模板。
- 使用 `unicode-math` 处理数学字体。
- Windows 的中文字体开启伪粗。
@@ -242,11 +323,15 @@
- 增加 `nomencl` 宏包的支持。
## [v5.4.5] - 2018-05-17
+
### Changed
+
- `\normalsize`: 调整公式和正文间距。
## [v5.4.4] - 2018-04-22
+
### Changed
+
- 删除 `arialtitle`,所有论文格式都一样。
- 让目录中的引用不影响正文中引用序号。
- 参考文献列表的页码使用 hyphen 取代 en dash。
@@ -254,40 +339,56 @@
- 允许连续两个文献引用使用连接号。
## [v5.4.2] - 2017-12-18
+
### Changed
+
- 删除 `\pozhehao`。
- 使用 degree 取代 type 选项。
## [v5.4.1] - 2017-12-04
+
### Changed
+
- bst 在 ctan 上不分路径,故加前缀。
## [v5.4.0] - 2017-12-3
+
### Changed
+
- 基于 `natbib` 的环境调整距离兼容性更好。
- `\bibliographystyle{<newbib>}` will cause `\bibstyle@newbib` to be called on THE NEXT LATEX RUN (via the aux file).
## [v5.3.2] - 2017-05-01
+
### Changed
+
- 定理环境格式设置(环境标题和环境正文字体设置)统一放置到 .cfg 文件中。
## [v5.3.1] - 2016-03-20
+
### Changed
+
- 使用 CTeX 默认中文字体配置,支持不同引擎。
- `ctex` 默认加载 `CJKspace`。
- 几乎没人主动安装 Arial 字体。
## [v5.3.0] - 2016-03-11
+
### Changed
+
- 更新到研究生院 2016.3 指南。
## [v5.2.3] - 2016-02-13
+
### Changed
+
- `\thu@def@fontsize`: 改写字体定义命令。
- 安全注释本科公式部分。
## [v5.2.2] - 2016-02-01
+
### Changed
+
- 不希望 `newtx` 修改 `\@makefnmark`。
- 利用 `environ` 的 `\Collect@Body`。
- 目录中标题和页码都是链接。
@@ -297,26 +398,34 @@
- 用 `environ` 封装的 `\Collect@Body`。
## [v5.2.1] - 2016-01-14
+
### Changed
+
- 使用 `newtx` 替换 `txfonts`。
- 使用 `newtx` 字体。
- `denotation`: 利用 `enumitem` 改造环境定义,更直观。
- `acknowledgement`: 用 `acknowledgement` 替换 `ack`。
## [v5.2.0] - 2016-01-11
+
### Changed
+
- `\title`: 增加 `\title` 排版翻译标题。
- `translationbib`: 增加翻译文献环境 `translationbib`。
- `\publicationskip`: 增加 `\publicationskip`。
## [v5.1.0] - 2015-12-27
+
### Changed
+
- `\thusetup`: 通过 `\thusetup` 统一设置封面信息。
- `\thu@first@titlepage`: 利用 `CJKfilltwosides` 优化封面排版。
- `\thu@first@titlepage`: 修改联合指导教师显示问题。
## [v5.0.0] - 2015-12-21
+
### Changed
+
- 使用 `kvoptions` 简化选项 type。
- norggedbottom 选项修改为 raggedbottom。
- 删除 `paralist` 选项。
@@ -324,25 +433,29 @@
- 不再将页面尺寸写入 dvi,因为已不支持 dvips, 而该方案会使得在使用 tikzexternalize 时外部 PDF 图片 BBox 不对。
- 用 `geometry` 简化设置。
- `\ps@thu@headings`: 利用 `fancyhdr` 设置页眉页脚。
-- 修正定理字样为黑体(#104)。
+- 修正定理字样为黑体([#104](https://github.com/tuna/thuthesis/issues/104))。
- 本科附录图表编号用-不用.(如图A-1,表A-2)。
- 用 `\ctexset` 来设置,替换复杂的 `\@startsection`。
-- 修正章节间距问题(#57)。
+- 修正章节间距问题([#57](https://github.com/tuna/thuthesis/issues/57))。
- 硕士博士论文目录只出现到第 3 级标题即可。其他未明确要求。
-- `\tableofcontents`: 修正学位论文中目录里节前缩进(#103)。
-- `\makecover`: 使用 `pdfpages` 宏包支持本硕博论文授权说明扫描版(#36)。
-- `acknowledgement`: 使用 pdfpages 宏包支持本硕博论文声明扫描版(#36)。
+- `\tableofcontents`: 修正学位论文中目录里节前缩进([#103](https://github.com/tuna/thuthesis/issues/103))。
+- `\makecover`: 使用 `pdfpages` 宏包支持本硕博论文授权说明扫描版([#36](https://github.com/tuna/thuthesis/issues/36))。
+- `acknowledgement`: 使用 pdfpages 宏包支持本硕博论文声明扫描版([#36](https://github.com/tuna/thuthesis/issues/36))。
- `\inlinecite`: 用 `\inlinecite` 替换 `\onlinecite`。为保证兼 容性,`\onlinecite` 会保留。
-- `achievements`: 博士后就不提在学期间了,不合适(#100)。
-- `achievements`: 让简历部分更符合格式指南和示例文件(#122)。
+- `achievements`: 博士后就不提在学期间了,不合适([#100](https://github.com/tuna/thuthesis/issues/100))。
+- `achievements`: 让简历部分更符合格式指南和示例文件([#122](https://github.com/tuna/thuthesis/issues/122))。
- `\shuji`: 扩展 `\shuji[<标题>][<作者>]`。
## [v4.8.1] - 2014-12-09
+
### Changed
+
- 按照 CTAN 的要求整理一下文件。
## [v4.8] - 2014-11-25
+
### Changed
+
- no need to load `indentfirst` directly since we use `ctex`.
- 内部调用 `ctex` 宏包,自动检测编译引擎。
- dvips method is deprecated. We ask their users to load it manually.
@@ -355,7 +468,9 @@
- 在 CJK 模式下用 `CJKspace` 保留中英文间空格。
## [v4.7] - 2012-06-12
+
### Changed
+
- 去掉 `hypernat` 依赖,`hyperref` 和 `natbib` 可以很好配合了。
- 修改本科生页脚间距与样例基本一致。
- `\ps@thu@headings`: 本科页码用小五号字。
@@ -368,7 +483,9 @@
- `\thu@makeabstract`: Bachelor sample uses Keywords w/o space `-_-`
## [v4.6] - 2011-10-22
+
### Changed
+
- 增加博士后文档部分。
- 使用手册更新。
- 增加 postdoctor 选项。
@@ -379,7 +496,9 @@
- `resume`: 支持可选参数,自己定义简历章节标题。
## [v4.5.2] - 2010-09-19
+
### Changed
+
- 研究生页面边距由 3.2cm 改为 3cm。
- 本科论文日期具体到日。
- `\makecover`: 本科封面和授权说明之间不要空白页。
@@ -387,28 +506,38 @@
- `acknowledgement`: 研究生论文的致谢和声明终于分开了。
## [v4.5.1] - 2009-01-06
+
### Changed
+
- 太好了,不用处理 `longtable` 的 `\caption` 了。
- `\listoftables*`: 更优雅的插图/表格索引,避免跟 `caption` 包冲 突。`\thu@listof` 相应修改。
## [v4.5] - 2009-01-04
+
### Changed
+
- 加入 XeTeX 支持,需要 `xeCJK`。
- 彻底转向 UTF-8,并支持 XeLaTeX。
- 增加 xetex, pdftex 选项。
- `\shuji`: 简化代码,同时支持 XeLaTeX。
## [v4.4.4] - 2008-06-12
+
### Changed
+
- 修复了一个从 v4.3 升级到 v4.4 过程中的丢失公式索引的 bug,原修改代码保留备忘。
## [v4.4.3] - 2008-06-09
+
### Changed
+
- `\thu@first@titlepage`: 修改本科生论文封面格式以符合新样例。
- `\thu@first@titlepage`: 修改本科生论文封面日期格式以符合新样例。
## [v4.4.2] - 2008-06-07
+
### Changed
+
- 本科生格式终于也开始用空格作为关键字分隔符了。
- 本科生签名之间距离改为 `\hskip1em`。
- `\thu@authorization@mk`: 修改本科生的授权部分,按照 2008 年的新样例。
@@ -416,7 +545,9 @@
- `\thu@makeabstract`: Bachelor English abstract format requires indent and no hang-indent.
## [v4.4] - 2008-06-18
+
### Changed
+
- 修复网址断字。
- `\backmatter`: 本科正文后的页码延续前面的阿拉伯数字,不再用罗马数 字。
- `\backmatter`: 本科取消了所有页眉。
@@ -430,23 +561,31 @@
- `\tableofcontents`: 本科章目录项一直用黑体(Arial)。
## [v4.3] - 2008-03-11
+
### Changed
+
- 子图引用时加括号。
## [v4.2] - 2008-03-07
+
### Changed
+
- `\eqref` 加括号。
- 调整证明环境的编号和结尾的方块。
- `\thu@doctor@engcover`: 博士英文封面补充联合导师。
## [v4.0] - 2007-11-08
+
### Changed
+
- `\tableofcontents`: 本科研究生目录字号行距都不同。
- **内部**密级前面终究还是不要五角星了。
- `\thu@authorization@mk`: 研究生的授权部分调整了一下,不知道老师为什么总爱修改 那些无关紧要的格式,郁闷。感谢 PMHT@newsmth 的认真比对。
## [v3.1] - 2007-10-09
+
### Changed
+
- 本科的目录又不要 arial 字体了。
- replace `mathptmx` with `txfonts`.
- 英文摘要标题要搞特殊化。
@@ -460,7 +599,9 @@
- `\thu@makeabstract`: 研究生关键词不再沉底。
## [v3.0] - 2007-05-13
+
### Changed
+
- 不用专门为本科论文生成“**提交**”版本了。
- 没有了综合论文训练页面,很多本科论文专用命令就消失了。
- 删除 submit 选项。
@@ -473,7 +614,9 @@
- `acknowledgement`: 本科论文声明部分图片扫描取消。
## [v2.6.4] - 2006-10-23
+
### Changed
+
- 增加 `neverdecrease` 选项。
- `\thu@makeabstract`: **Keywords** but not **Key words**.
- `\listoftables*`: 增加 `\listoffigures*`,`\listoftables*`。
@@ -481,12 +624,16 @@
- 调整参考文献标签宽度,使得条目增多时仍能对齐。
## [v2.6.3] - 2006-07-01
+
### Changed
+
- `\thu@makeabstract`: 为本科正确设置目录及以后的页码。
- `acknowledgement`: 重画双虚线,自适应页面宽度。
## [v2.6.2] - 2006-06-20
+
### Changed
+
- 改正 groupmembers 的拼写错误。
- 去掉 `paralist` 的 `newitem` 和 `newenum` 选项,因为默认是打开的。
- `\thu@def@fontsize`: 引入此命令重新定义字号。
@@ -500,11 +647,15 @@
- `\equcaption`: 此命令配合 `amsmath` 命令基本可以满足所有 公式需要。
## [v2.6.1] - 2006-06-16
+
### Changed
+
- 取消 `thubib.bst` 中 inbook 类 volume 后的页 码。
## [v2.6] - 2006-06-09
+
### Changed
+
- 增加 dvipdfm 选项。
- 增加 `longtable`。
- 去除 hyperref 选项,等待全局传递。
@@ -513,7 +664,9 @@
- `\thu@first@titlepage`: 本科生题目加长,最多 24 个字。
## [v2.5.3] - 2006-06-08
+
### Changed
+
- submit 选项的一个笔误。
- `\backmatter`: 第一章永远右开。
- 不管 caption 出现在什么位置,`\aboveskip` 总是出现在标题和浮动体之间的距离。
@@ -522,7 +675,9 @@
- `\equcaption`: 取消 `\equcaption` 的参数
## [v2.5.2] - 2006-06-01
+
### Changed
+
- 更改默认列表距离。
- 上一个版本忘了把研究生的公式编号排除。
- `\thu@chapter*`: 定义自己的 `\thu@chapter*`。
@@ -534,7 +689,9 @@
- `resume`: 研究生的个人介绍要右开。
## [v2.5.1] - 2006-05-28
+
### Changed
+
- 如果选项设置了 dvips,但是用 PDFLaTeX 编译,报错。
- 根据教务处的新要求调整附录部分。
- 参考文献中杂志文章如果没有卷号,那么页码直接跟在 年份后面,并用句点分割。在 `thubib.bst` 中增加 output.year 函数。
@@ -560,7 +717,9 @@
- `resume`: 教务处和研究生院非要搞的不一样!
## [v2.5] - 2006-05-20
+
### Changed
+
- 对本科论文进行大幅度的重写,因为教务处修改了格式要求。
- 重新整理代码,使其布局更易读。
- 增加本科论文的提交选项 submit。
@@ -583,16 +742,22 @@
- 不用 `\CJKcaption`,在导言区直接引入配置文件。
## [v2.4.2] - 2006-04-18
+
### Changed
+
- 去掉参考文献第二个作者后面烦人的逗号。
## [v2.4.1] - 2006-04-17
+
### Changed
+
- 2.4 忘了把关键词的 tabular 改成 thu@tabular。
- 参考文献最后一个作者前是逗号而不是 and。
## [v2.4] - 2006-04-15
+
### Changed
+
- Fill more pdf info. with `\hypersetup`.
- 自动隐藏密级为内部时后面的五角星。
- 增加“注释(Remark)”环境。
@@ -616,7 +781,9 @@
- 参考文献间距调小一点,label 长度增加一点,以便让超过 100 的参考文献更好地对齐。
## [v2.3] - 2006-04-09
+
### Changed
+
- Fix a great bug: `\PassOptionsToClass` and `\LoadClass` rather than `\PassOptionToPackage` and `\LoadPackage`.
- Reorganize the codes in cover, make the pagestyle more readable.
- Add gbk2uni into the document.
@@ -629,14 +796,18 @@
- Change the brace in the cover.
## [v2.2] - 2006-03-26
+
### Changed
+
- Adjust margins. How bad it is to simulate MS WORD!.
- Add bachelor training overview details supporting.
- CJK support in preamble.
- Adjust hyperref to avoid boxes around links.
## [v2.1] - 2006-03-03
+
### Changed
+
- Add support to bachelor thesis.
- Remove `fancyhdr` and `geometry`.
- Redefine footnote marks.
@@ -651,11 +822,15 @@
- `\makecover`: 分成几个小模块来搞,不然这个 macro 太大了,看不过来。
## [v2.0e] - 2005-12-18
+
### Changed
+
- `denotation`: 主要符号表定义为一个 list,用起来方便。
## [v2.0] - 2005-12-20
+
### Changed
+
- `\ps@thu@headings`: 以前的太乱了,重新整理过清晰多了。
- `\tableofcontents`: 附录的目录项需要调整一下。以及公式编号方式等等。
- 增加了封面密级,增加博士封面支持
@@ -664,38 +839,53 @@
- `resume`: 最后决定将 resume 定义为环境。这样与前面的主要符号 表、致谢等对应。
## [v1.5] - 2005-12-16
+
### Changed
+
- `acknowledgement`: 在那些不显示编号的章节前面先执行一次 `\cleardoublepage`,使新开章节的页码到达正确的状态。否则会因为 `\addcontentsline` 在 chapter 之前而导致目录页码错误。
- `resume`: 增加个人简历章节的命令,去掉主文件中需要重新 定义 `\cleardoublepage` 和自己写 `\markboth`,`\addcontentsline` 的部分。
## [v1.4rc1] - 2005-12-14
+
### Changed
+
- I do not know why `\thu@authorizationaddon` does not work now for v1.3, while it's fine in v1.2. Temporarily, I remove the directive :(. There might be better solution. Other changes: add `config` option to subfig to be compatible with subfigure. add `courier` package for tt font.
- I have to put all chinese chars into cfg, otherwise they would not appear.
## [v1.4] - 2005-12-05
+
### Changed
+
- Fix the problem of **chinese**, which is because both CJK and everysel redefine the `\selectfont`. So, a not so good workaround is to merge them up. Add `shuji.tex` example. Add `\pozhehao` command.
## [v1.3] - 2005-11-14
+
### Changed
+
- Replace `subfigure` with `subfig`, replace `caption2` with `caption`, add details about using figure are in the example.
## [v1.2] - 2005-11-04
+
### Changed
+
- Remove `fancyref`; Remove `ucite` and implement `\onlinecite`; use package `arial` or `helvet` selectively.
## [v1.1] - 2005-11-03
+
### Changed
+
- Initial version, migrate from the old ``Bao--Pan'' version. Make the template a class instead of package.
## [v1.0] - 2005-07-06
+
### Changed
+
- Please refer to ``Bao--Pan'' version.
-[Unreleased]: https://github.com/tuna/thuthesis/compare/v7.2.3...HEAD
+[Unreleased]: https://github.com/tuna/thuthesis/compare/v7.2.4...HEAD
+[v7.2.4]: https://github.com/tuna/thuthesis/compare/v7.2.3...v7.2.4
[v7.2.3]: https://github.com/tuna/thuthesis/compare/v7.2.2...v7.2.3
[v7.2.2]: https://github.com/tuna/thuthesis/compare/v7.2.1...v7.2.2
[v7.2.1]: https://github.com/tuna/thuthesis/compare/v7.2.0...v7.2.1
diff --git a/macros/latex/contrib/thuthesis/README.md b/macros/latex/contrib/thuthesis/README.md
index 455b858f95..c84c7f409f 100644
--- a/macros/latex/contrib/thuthesis/README.md
+++ b/macros/latex/contrib/thuthesis/README.md
@@ -15,10 +15,6 @@ Scroll down for the English version of README.
**由于模板升级频繁,在开始使用和提问前,请确保您已经认真完整地阅读了使用说明文档和示例代码。**
-**由于模板升级频繁,在开始使用和提问前,请确保您已经认真完整地阅读了使用说明文档和示例代码。**
-
-**由于模板升级频繁,在开始使用和提问前,请确保您已经认真完整地阅读了使用说明文档和示例代码。**
-
## 下载
推荐下载**发布版**模板,里面包括具体使用说明以及示例文档:
@@ -37,6 +33,8 @@ Scroll down for the English version of README.
* [Overleaf](https://www.overleaf.com/latex/templates/thuthesis-tsinghua-university-thesis-latex-template/wddqnwbyhtnk):Overleaf 的模板。
* 开发版:[GitHub](https://github.com/tuna/thuthesis)
+**任何在其他途径分发的 ThuThesis(包含其变体或衍生物)均不是官方版本,请谨慎使用。**
+
## 更新日志
每个版本的详细更新日志,请见 [CHANGELOG.md](CHANGELOG.md)。使用文档中也包含了这一内容。
@@ -107,6 +105,8 @@ Developer versions contain only source code but no pre-compiled `cls` file and d
* [Overleaf Template](https://www.overleaf.com/latex/templates/thuthesis-tsinghua-university-thesis-latex-template/wddqnwbyhtnk)
* Developer versions: [GitHub](https://github.com/tuna/thuthesis)
+**ThuThesis (including its variants / derivatives) distributed in any other way is NOT an official version. Use at your own risk.**
+
## Changelog
See [CHANGELOG.md](CHANGELOG.md) for detailed changes in each release. They are also included in the usage documentation.
diff --git a/macros/latex/contrib/thuthesis/data/appendix-translation.tex b/macros/latex/contrib/thuthesis/data/appendix-translation.tex
index 812cfcc767..0ca7d15264 100644
--- a/macros/latex/contrib/thuthesis/data/appendix-translation.tex
+++ b/macros/latex/contrib/thuthesis/data/appendix-translation.tex
@@ -62,6 +62,13 @@
文献引用示例\cite{abrahams99tex}。
+\appendix
+
+\section{附录}
+
+附录的内容。
+
+
% 书面翻译的参考文献
\bibliographystyle{unsrtnat}
\bibliography{ref/appendix}
diff --git a/macros/latex/contrib/thuthesis/data/chap04.tex b/macros/latex/contrib/thuthesis/data/chap04.tex
index a7fcc1439f..b07ce4dc96 100644
--- a/macros/latex/contrib/thuthesis/data/chap04.tex
+++ b/macros/latex/contrib/thuthesis/data/chap04.tex
@@ -47,7 +47,7 @@
\thusetup{
cite-style = author-year,
}
-\begin{tabular}{l@{\quad$\Rightarrow$\quad}l}
+\begin{tabular}{l@{\space$\Rightarrow$\space}l}
\verb|\cite{zhangkun1994}| & \cite{zhangkun1994} \\
\verb|\citet{zhangkun1994}| & \citet{zhangkun1994} \\
\verb|\citep{zhangkun1994}| & \citep{zhangkun1994} \\
diff --git a/macros/latex/contrib/thuthesis/ref/appendix.bib b/macros/latex/contrib/thuthesis/ref/appendix.bib
index 1e4cc0daef..0f9ae22352 100644
--- a/macros/latex/contrib/thuthesis/ref/appendix.bib
+++ b/macros/latex/contrib/thuthesis/ref/appendix.bib
@@ -5,7 +5,7 @@
year = 1990,
}
-@incollection{salomon1995advanced,
+@book{salomon1995advanced,
author = {David Salomon},
title = {The advanced {\TeX}book},
address = {New York},
diff --git a/macros/latex/contrib/thuthesis/ref/refs.bib b/macros/latex/contrib/thuthesis/ref/refs.bib
index 7c397888d5..6b51f03003 100644
--- a/macros/latex/contrib/thuthesis/ref/refs.bib
+++ b/macros/latex/contrib/thuthesis/ref/refs.bib
@@ -41,7 +41,9 @@
@patent{jiangxizhou1980,
author = {姜锡洲},
- title = {一种温热外敷药制备方案: 中国, 88105607.3},
+ title = {一种温热外敷药制备方案},
+ address = {中国},
+ number = {88105607.3},
date = {1980-07-26},
key = {jiang1 xi1 zhou1},
}
diff --git a/macros/latex/contrib/thuthesis/spine.pdf b/macros/latex/contrib/thuthesis/spine.pdf
index 63eef753e0..6f9d37e2ed 100644
--- a/macros/latex/contrib/thuthesis/spine.pdf
+++ b/macros/latex/contrib/thuthesis/spine.pdf
Binary files differ
diff --git a/macros/latex/contrib/thuthesis/thusetup.tex b/macros/latex/contrib/thuthesis/thusetup.tex
index dc74d148bd..718667f969 100644
--- a/macros/latex/contrib/thuthesis/thusetup.tex
+++ b/macros/latex/contrib/thuthesis/thusetup.tex
@@ -156,10 +156,10 @@
% \bibliographystyle{thuthesis-bachelor}
% 参考文献使用 BibLaTeX 宏包
-% \usepackage[backend=biber,style=thuthesis-numeric]{biblatex}
-% \usepackage[backend=biber,style=thuthesis-author-year]{biblatex}
-% \usepackage[backend=biber,style=apa]{biblatex}
-% \usepackage[backend=biber,style=mla-new]{biblatex}
+% \usepackage[style=thuthesis-numeric]{biblatex}
+% \usepackage[style=thuthesis-author-year]{biblatex}
+% \usepackage[style=apa]{biblatex}
+% \usepackage[style=mla-new]{biblatex}
% 声明 BibLaTeX 的数据库
% \addbibresource{ref/refs.bib}
diff --git a/macros/latex/contrib/thuthesis/thuthesis-author-year.bbx b/macros/latex/contrib/thuthesis/thuthesis-author-year.bbx
index 47ec9ea815..026e280cb1 100644
--- a/macros/latex/contrib/thuthesis/thuthesis-author-year.bbx
+++ b/macros/latex/contrib/thuthesis/thuthesis-author-year.bbx
@@ -6,7 +6,6 @@
\ExecuteBibliographyOptions{
gbnamefmt = lowercase,
gbpub = false,
- gbalign = left,
}
\defbibenvironment{bibliography}
@@ -18,3 +17,33 @@
\setlength{\parsep}{\bibparsep}}}
{\endlist}
{\item}
+
+%
+% 重设专利title的输出,将文献类型标识符输出出去
+%
+\renewbibmacro*{patenttitle}{%原输出来自biblatex.def文件
+ \ifboolexpr{%
+ test{\iffieldundef{title}}%
+ and%
+ test{\iffieldundef{subtitle}}%
+ }%
+ {}%
+ {\printtext[title]{\bibtitlefont%
+ \printfield[titlecase]{title}%
+ \ifboolexpr{test {\iffieldundef{subtitle}}}
+ {}{\setunit{\subtitlepunct}%
+ \printfield[titlecase]{subtitle}}%
+ \iffieldundef{titleaddon}{}
+ {\setunit{\subtitlepunct}\printfield{titleaddon}}%
+ % \setunit{\subtitlepunct}\printfield{number}%写专利号
+ \setunit{\subtitlepunct}%
+ \iflistundef{location}{}
+ {\printlist{location}\setunit{\addcomma\space}}% 专利国别
+ \printfield{number}%写专利号
+ \iftoggle{bbx:gbtype}{\printfield[gbtypeflag]{usera}}{}%
+ %\iffieldundef{booktitle}{\newunit}{}%当title是析出时,不要标点
+ %\newunit
+ }%
+}%
+\clearlist{location}\clearlist{address}%
+}
diff --git a/macros/latex/contrib/thuthesis/thuthesis-author-year.bst b/macros/latex/contrib/thuthesis/thuthesis-author-year.bst
index d25269b8e3..514368e842 100644
--- a/macros/latex/contrib/thuthesis/thuthesis-author-year.bst
+++ b/macros/latex/contrib/thuthesis/thuthesis-author-year.bst
@@ -4,11 +4,11 @@
%%
%% The original source files were:
%%
-%% gbt7714.dtx (with options: `2015,thu,authoryear')
+%% gbt7714.dtx (with options: `2015,thu,author-year')
%% -------------------------------------------------------------------
%% GB/T 7714—2015 BibTeX Style
-%% https://github.com/CTeX-org/gbt7714-bibtex-style
-%% Version: 2021/04/03 v2.1.1
+%% https://github.com/zepinglee/gbt7714-bibtex-style
+%% Version: 2021/12/08 v2.1.3
%% -------------------------------------------------------------------
%% Copyright (C) 2016—2021 by Zeping Lee <zepinglee AT gmail.com>
%% -------------------------------------------------------------------
@@ -29,9 +29,11 @@ INTEGERS {
terms.in.macro
year.after.author
period.after.author
+ italic.book.title
sentence.case.title
link.title
title.in.journal
+ show.patent.country
show.mark
space.before.mark
show.medium.type
@@ -43,12 +45,14 @@ INTEGERS {
show.missing.address.publisher
space.before.pages
only.start.page
+ wave.dash.in.pages
show.urldate
show.url
show.doi
show.preprint
show.note
show.english.translation
+ end.with.period
lang.zh.order
lang.ja.order
lang.en.order
@@ -66,9 +70,11 @@ FUNCTION {load.config}
#0 'terms.in.macro :=
#1 'year.after.author :=
#0 'period.after.author :=
+ #0 'italic.book.title :=
#1 'sentence.case.title :=
#0 'link.title :=
#1 'title.in.journal :=
+ #1 'show.patent.country :=
#1 'show.mark :=
#0 'space.before.mark :=
#1 'show.medium.type :=
@@ -80,12 +86,14 @@ FUNCTION {load.config}
#0 'show.missing.address.publisher :=
#1 'space.before.pages :=
#0 'only.start.page :=
+ #0 'wave.dash.in.pages :=
#1 'show.urldate :=
#1 'show.url :=
#1 'show.doi :=
- #0 'show.preprint :=
+ #1 'show.preprint :=
#0 'show.note :=
#0 'show.english.translation :=
+ #1 'end.with.period :=
#1 'lang.zh.order :=
#2 'lang.ja.order :=
#3 'lang.en.order :=
@@ -341,7 +349,10 @@ FUNCTION {output.check}
}
FUNCTION {fin.entry}
-{ add.period$
+{ end.with.period
+ 'add.period$
+ 'skip$
+ if$
write$
show.english.translation entry.lang lang.zh = and
{ ")"
@@ -428,10 +439,18 @@ FUNCTION {field.or.null}
if$
}
-FUNCTION {italicize}
+FUNCTION {emphasize}
{ duplicate$ empty$
{ pop$ "" }
- { "\textit{" swap$ * "}" * }
+ { "\emph{" swap$ * "}" * }
+ if$
+}
+
+FUNCTION {format.btitle}
+{ italic.book.title
+ entry.lang lang.en = and
+ 'emphasize
+ 'skip$
if$
}
@@ -566,7 +585,7 @@ FUNCTION {format.name}
{ bbl.et.al }
{ t get.str.lang 'name.lang :=
name.lang lang.en =
- { t #1 "{vv~}{ll}{~f{~}}" format.name$
+ { t #1 "{vv~}{ll}{ f{~}}" format.name$
uppercase.name
{ "u" change.case$ }
'skip$
@@ -756,7 +775,7 @@ FUNCTION {add.link}
{ url empty$ not
{ "\href{" url * "}{" * swap$ * "}" * }
{ doi empty$ not
- { "\href{http://dx.doi.org/" doi * "}{" * swap$ * "}" * }
+ { "\href{https://doi.org/" doi * "}{" * swap$ * "}" * }
'skip$
if$
}
@@ -772,7 +791,25 @@ FUNCTION {format.title}
'skip$
if$
entry.numbered number empty$ not and
- { bbl.colon * number * }
+ { bbl.colon *
+ type$ "patent" = show.patent.country and
+ { address empty$ not
+ { address * ", " * }
+ { location empty$ not
+ { location * ", " * }
+ { entry.lang lang.zh =
+ { "中国" * ", " * }
+ 'skip$
+ if$
+ }
+ if$
+ }
+ if$
+ }
+ 'skip$
+ if$
+ number *
+ }
'skip$
if$
link.title
@@ -917,6 +954,7 @@ FUNCTION {format.series.vol.num.title}
}
{ format.title.vol.num }
if$
+ format.btitle
link.title
'add.link
'skip$
@@ -948,6 +986,7 @@ FUNCTION {format.series.vol.num.booktitle}
}
{ format.booktitle.vol.num }
if$
+ format.btitle
in.booktitle
{ duplicate$ empty$ not entry.lang lang.en = and
{ "In: " swap$ * }
@@ -989,16 +1028,15 @@ FUNCTION {abbreviate}
if$
}
-FUNCTION {format.journal}
-{ ""
- short.journal
+FUNCTION {get.journal.title}
+{ short.journal
{ shortjournal empty$ not
- { shortjournal * }
+ { shortjournal }
{ journal empty$ not
- { journal * abbreviate }
+ { journal abbreviate }
{ journaltitle empty$ not
- { journaltitle * abbreviate }
- 'skip$
+ { journaltitle abbreviate }
+ { "" }
if$
}
if$
@@ -1006,18 +1044,33 @@ FUNCTION {format.journal}
if$
}
{ journal empty$ not
- { journal * }
+ { journal }
{ journaltitle empty$ not
- { journaltitle * }
- 'skip$
+ { journaltitle }
+ { shortjournal empty$ not
+ { shortjournal }
+ { "" }
+ if$
+ }
if$
}
if$
}
if$
+}
+
+FUNCTION {check.arxiv.preprint}
+{ #1 #5 substring$ "l" change.case$ "arxiv" =
+ { #1 }
+ { #0 }
+ if$
+}
+
+FUNCTION {format.journal}
+{ get.journal.title
duplicate$ empty$ not
{ italic.journal entry.lang lang.en = and
- 'italicize
+ 'emphasize
'skip$
if$
}
@@ -1092,7 +1145,7 @@ FUNCTION {format.edition}
{ edition change.sentence.case 's :=
s "Revised" = s "Revised edition" = or
{ "Rev. ed." }
- { s " ed." *}
+ { s " ed." * }
if$
}
{ edition }
@@ -1282,11 +1335,16 @@ FUNCTION {format.periodical.year}
}
FUNCTION {format.date}
-{ type$ "patent" = type$ "newspaper" = or
- date empty$ not and
- { date }
- { year field.or.null
- extra.label *
+{ date empty$ not
+ { type$ "patent" = type$ "newspaper" = or
+ { date }
+ { format.year }
+ if$
+ }
+ { year empty$ not
+ { format.year }
+ { "" }
+ if$
}
if$
}
@@ -1299,9 +1357,9 @@ FUNCTION {format.editdate}
}
FUNCTION {format.urldate}
-{ urldate empty$ not
- show.urldate show.url and is.pure.electronic or and
- url empty$ not and
+{ show.urldate show.url and entry.url empty$ not and
+ is.pure.electronic or
+ urldate empty$ not and
{ "\allowbreak[" urldate * "]" * }
{ "" }
if$
@@ -1312,7 +1370,10 @@ FUNCTION {hyphenate}
""
{ t empty$ not }
{ t #1 #1 substring$ "-" =
- { "-" *
+ { wave.dash.in.pages
+ { "~" * }
+ { "-" * }
+ if$
{ t #1 #1 substring$ "-" = }
{ t #2 global.max$ substring$ 't := }
while$
@@ -1432,12 +1493,9 @@ FUNCTION {check.url}
if$
}
-FUNCTION {format.url}
-{ entry.url
-}
-
FUNCTION {output.url}
-{ entry.url empty$ not
+{ show.url is.pure.electronic or
+ entry.url empty$ not and
{ new.block
entry.url output
}
@@ -1538,9 +1596,9 @@ FUNCTION {check.electronic}
}
FUNCTION {format.eprint}
-{ eprinttype empty$ not
- { eprinttype }
- { archivePrefix empty$ not
+{ archivePrefix empty$ not
+ { archivePrefix }
+ { eprinttype empty$ not
{ archivePrefix }
{ "" }
if$
@@ -1731,7 +1789,7 @@ FUNCTION {periodical}
fin.entry
}
-FUNCTION {article}
+FUNCTION {journal.article}
{ output.bibitem
output.translation
format.authors output
@@ -1865,7 +1923,7 @@ FUNCTION {preprint}
new.block
title.in.journal
{ format.series.vol.num.title "title" output.check
- "Z" set.entry.mark
+ "A" set.entry.mark
format.mark "" output.after
new.block
}
@@ -1875,13 +1933,18 @@ FUNCTION {preprint}
new.sentence
format.edition output
new.block
- output.eprint
year.after.author not
- { format.year "year" output.check }
+ { date empty$
+ { format.date output }
+ 'skip$
+ if$
+ }
'skip$
if$
format.pages bbl.pages.colon output.after
+ format.editdate "" output.after
format.urldate "" output.after
+ output.eprint
output.url
new.block
format.note output
@@ -1889,13 +1952,19 @@ FUNCTION {preprint}
}
FUNCTION {misc}
-{ journal empty$ not
- 'article
- { booktitle empty$ not
+{ get.journal.title
+ duplicate$ empty$ not
+ { check.arxiv.preprint
+ 'preprint
+ 'journal.article
+ if$
+ }
+ { pop$
+ booktitle empty$ not
'incollection
{ publisher empty$ not
'monograph
- { eprint empty$ not show.preprint and
+ { eprint empty$ not archivePrefix empty$ not or
'preprint
{ entry.is.electronic
'electronic
@@ -1920,6 +1989,8 @@ FUNCTION {archive}
misc
}
+FUNCTION {article} { misc }
+
FUNCTION {book} { monograph }
FUNCTION {booklet} { book }
@@ -1948,6 +2019,8 @@ FUNCTION {inproceedings}
FUNCTION {conference} { inproceedings }
+FUNCTION {legislation} { archive }
+
FUNCTION {map}
{ "CM" set.entry.mark
misc
@@ -2407,25 +2480,42 @@ FUNCTION {presort}
'sort.key$ :=
}
-STRINGS { longest.label last.label next.extra }
+STRINGS { longest.label last.label next.extra last.extra.label }
-INTEGERS { longest.label.width last.extra.num number.label }
+INTEGERS { longest.label.width number.label }
FUNCTION {initialize.longest.label}
{ "" 'longest.label :=
#0 int.to.chr$ 'last.label :=
"" 'next.extra :=
#0 'longest.label.width :=
- #0 'last.extra.num :=
#0 'number.label :=
+ "" 'last.extra.label :=
}
FUNCTION {forward.pass}
-{ last.label short.label =
- { last.extra.num #1 + 'last.extra.num :=
- last.extra.num int.to.chr$ 'extra.label :=
+{
+ last.label short.label =
+ { "" 'extra.label :=
+ last.extra.label text.length$ 'charptr :=
+ { last.extra.label charptr #1 substring$ "z" =
+ charptr #0 > and
+ }
+ { "a" extra.label * 'extra.label :=
+ charptr #1 - 'charptr :=
+ }
+ while$
+ charptr #0 >
+ { last.extra.label charptr #1 substring$ chr.to.int$ #1 + int.to.chr$
+ extra.label * 'extra.label :=
+ last.extra.label #1 charptr #1 - substring$
+ extra.label * 'extra.label :=
+ }
+ { "a" extra.label * 'extra.label := }
+ if$
+ extra.label 'last.extra.label :=
}
- { "a" chr.to.int$ 'last.extra.num :=
+ { "a" 'last.extra.label :=
"" 'extra.label :=
short.label 'last.label :=
}
@@ -2434,7 +2524,8 @@ FUNCTION {forward.pass}
}
FUNCTION {reverse.pass}
-{ next.extra "b" =
+{
+ next.extra "b" =
{ "a" 'extra.label := }
'skip$
if$
diff --git a/macros/latex/contrib/thuthesis/thuthesis-bachelor.bst b/macros/latex/contrib/thuthesis/thuthesis-bachelor.bst
index 5c08210cb3..78c81e628b 100644
--- a/macros/latex/contrib/thuthesis/thuthesis-bachelor.bst
+++ b/macros/latex/contrib/thuthesis/thuthesis-bachelor.bst
@@ -4,11 +4,11 @@
%%
%% The original source files were:
%%
-%% gbt7714.dtx (with options: `2015,numerical,noslsn')
+%% gbt7714.dtx (with options: `2015,numerical')
%% -------------------------------------------------------------------
%% GB/T 7714—2015 BibTeX Style
-%% https://github.com/CTeX-org/gbt7714-bibtex-style
-%% Version: 2021/04/03 v2.1.1
+%% https://github.com/zepinglee/gbt7714-bibtex-style
+%% Version: 2021/12/08 v2.1.3
%% -------------------------------------------------------------------
%% Copyright (C) 2016—2021 by Zeping Lee <zepinglee AT gmail.com>
%% -------------------------------------------------------------------
@@ -29,9 +29,11 @@ INTEGERS {
terms.in.macro
year.after.author
period.after.author
+ italic.book.title
sentence.case.title
link.title
title.in.journal
+ show.patent.country
show.mark
space.before.mark
show.medium.type
@@ -43,12 +45,14 @@ INTEGERS {
show.missing.address.publisher
space.before.pages
only.start.page
+ wave.dash.in.pages
show.urldate
show.url
show.doi
show.preprint
show.note
show.english.translation
+ end.with.period
}
FUNCTION {load.config}
@@ -61,9 +65,11 @@ FUNCTION {load.config}
#0 'terms.in.macro :=
#0 'year.after.author :=
#1 'period.after.author :=
+ #0 'italic.book.title :=
#1 'sentence.case.title :=
#0 'link.title :=
#1 'title.in.journal :=
+ #0 'show.patent.country :=
#1 'show.mark :=
#0 'space.before.mark :=
#1 'show.medium.type :=
@@ -75,12 +81,14 @@ FUNCTION {load.config}
#0 'show.missing.address.publisher :=
#1 'space.before.pages :=
#0 'only.start.page :=
+ #0 'wave.dash.in.pages :=
#1 'show.urldate :=
#1 'show.url :=
#1 'show.doi :=
- #0 'show.preprint :=
+ #1 'show.preprint :=
#0 'show.note :=
#0 'show.english.translation :=
+ #1 'end.with.period :=
}
ENTRY
@@ -331,7 +339,10 @@ FUNCTION {output.check}
}
FUNCTION {fin.entry}
-{ add.period$
+{ end.with.period
+ 'add.period$
+ 'skip$
+ if$
write$
show.english.translation entry.lang lang.zh = and
{ ")"
@@ -418,10 +429,18 @@ FUNCTION {field.or.null}
if$
}
-FUNCTION {italicize}
+FUNCTION {emphasize}
{ duplicate$ empty$
{ pop$ "" }
- { "\textit{" swap$ * "}" * }
+ { "\emph{" swap$ * "}" * }
+ if$
+}
+
+FUNCTION {format.btitle}
+{ italic.book.title
+ entry.lang lang.en = and
+ 'emphasize
+ 'skip$
if$
}
@@ -556,7 +575,7 @@ FUNCTION {format.name}
{ bbl.et.al }
{ t get.str.lang 'name.lang :=
name.lang lang.en =
- { t #1 "{vv~}{ll}{~f{~}}" format.name$
+ { t #1 "{vv~}{ll}{ f{~}}" format.name$
uppercase.name
{ "u" change.case$ }
'skip$
@@ -746,7 +765,7 @@ FUNCTION {add.link}
{ url empty$ not
{ "\href{" url * "}{" * swap$ * "}" * }
{ doi empty$ not
- { "\href{http://dx.doi.org/" doi * "}{" * swap$ * "}" * }
+ { "\href{https://doi.org/" doi * "}{" * swap$ * "}" * }
'skip$
if$
}
@@ -762,7 +781,25 @@ FUNCTION {format.title}
'skip$
if$
entry.numbered number empty$ not and
- { bbl.colon * number * }
+ { bbl.colon *
+ type$ "patent" = show.patent.country and
+ { address empty$ not
+ { address * ", " * }
+ { location empty$ not
+ { location * ", " * }
+ { entry.lang lang.zh =
+ { "中国" * ", " * }
+ 'skip$
+ if$
+ }
+ if$
+ }
+ if$
+ }
+ 'skip$
+ if$
+ number *
+ }
'skip$
if$
link.title
@@ -907,6 +944,7 @@ FUNCTION {format.series.vol.num.title}
}
{ format.title.vol.num }
if$
+ format.btitle
link.title
'add.link
'skip$
@@ -938,6 +976,7 @@ FUNCTION {format.series.vol.num.booktitle}
}
{ format.booktitle.vol.num }
if$
+ format.btitle
in.booktitle
{ duplicate$ empty$ not entry.lang lang.en = and
{ "In: " swap$ * }
@@ -979,16 +1018,15 @@ FUNCTION {abbreviate}
if$
}
-FUNCTION {format.journal}
-{ ""
- short.journal
+FUNCTION {get.journal.title}
+{ short.journal
{ shortjournal empty$ not
- { shortjournal * }
+ { shortjournal }
{ journal empty$ not
- { journal * abbreviate }
+ { journal abbreviate }
{ journaltitle empty$ not
- { journaltitle * abbreviate }
- 'skip$
+ { journaltitle abbreviate }
+ { "" }
if$
}
if$
@@ -996,18 +1034,33 @@ FUNCTION {format.journal}
if$
}
{ journal empty$ not
- { journal * }
+ { journal }
{ journaltitle empty$ not
- { journaltitle * }
- 'skip$
+ { journaltitle }
+ { shortjournal empty$ not
+ { shortjournal }
+ { "" }
+ if$
+ }
if$
}
if$
}
if$
+}
+
+FUNCTION {check.arxiv.preprint}
+{ #1 #5 substring$ "l" change.case$ "arxiv" =
+ { #1 }
+ { #0 }
+ if$
+}
+
+FUNCTION {format.journal}
+{ get.journal.title
duplicate$ empty$ not
{ italic.journal entry.lang lang.en = and
- 'italicize
+ 'emphasize
'skip$
if$
}
@@ -1082,7 +1135,7 @@ FUNCTION {format.edition}
{ edition change.sentence.case 's :=
s "Revised" = s "Revised edition" = or
{ "Rev. ed." }
- { s " ed." *}
+ { s " ed." * }
if$
}
{ edition }
@@ -1272,11 +1325,16 @@ FUNCTION {format.periodical.year}
}
FUNCTION {format.date}
-{ type$ "patent" = type$ "newspaper" = or
- date empty$ not and
- { date }
- { year field.or.null
- extra.label *
+{ date empty$ not
+ { type$ "patent" = type$ "newspaper" = or
+ { date }
+ { format.year }
+ if$
+ }
+ { year empty$ not
+ { format.year }
+ { "" }
+ if$
}
if$
}
@@ -1289,9 +1347,9 @@ FUNCTION {format.editdate}
}
FUNCTION {format.urldate}
-{ urldate empty$ not
- show.urldate show.url and is.pure.electronic or and
- url empty$ not and
+{ show.urldate show.url and entry.url empty$ not and
+ is.pure.electronic or
+ urldate empty$ not and
{ "\allowbreak[" urldate * "]" * }
{ "" }
if$
@@ -1302,7 +1360,10 @@ FUNCTION {hyphenate}
""
{ t empty$ not }
{ t #1 #1 substring$ "-" =
- { "-" *
+ { wave.dash.in.pages
+ { "~" * }
+ { "-" * }
+ if$
{ t #1 #1 substring$ "-" = }
{ t #2 global.max$ substring$ 't := }
while$
@@ -1422,12 +1483,9 @@ FUNCTION {check.url}
if$
}
-FUNCTION {format.url}
-{ entry.url
-}
-
FUNCTION {output.url}
-{ entry.url empty$ not
+{ show.url is.pure.electronic or
+ entry.url empty$ not and
{ new.block
entry.url output
}
@@ -1528,9 +1586,9 @@ FUNCTION {check.electronic}
}
FUNCTION {format.eprint}
-{ eprinttype empty$ not
- { eprinttype }
- { archivePrefix empty$ not
+{ archivePrefix empty$ not
+ { archivePrefix }
+ { eprinttype empty$ not
{ archivePrefix }
{ "" }
if$
@@ -1721,7 +1779,7 @@ FUNCTION {periodical}
fin.entry
}
-FUNCTION {article}
+FUNCTION {journal.article}
{ output.bibitem
output.translation
format.authors output
@@ -1855,7 +1913,7 @@ FUNCTION {preprint}
new.block
title.in.journal
{ format.series.vol.num.title "title" output.check
- "Z" set.entry.mark
+ "A" set.entry.mark
format.mark "" output.after
new.block
}
@@ -1865,13 +1923,18 @@ FUNCTION {preprint}
new.sentence
format.edition output
new.block
- output.eprint
year.after.author not
- { format.year "year" output.check }
+ { date empty$
+ { format.date output }
+ 'skip$
+ if$
+ }
'skip$
if$
format.pages bbl.pages.colon output.after
+ format.editdate "" output.after
format.urldate "" output.after
+ output.eprint
output.url
new.block
format.note output
@@ -1879,13 +1942,19 @@ FUNCTION {preprint}
}
FUNCTION {misc}
-{ journal empty$ not
- 'article
- { booktitle empty$ not
+{ get.journal.title
+ duplicate$ empty$ not
+ { check.arxiv.preprint
+ 'preprint
+ 'journal.article
+ if$
+ }
+ { pop$
+ booktitle empty$ not
'incollection
{ publisher empty$ not
'monograph
- { eprint empty$ not show.preprint and
+ { eprint empty$ not archivePrefix empty$ not or
'preprint
{ entry.is.electronic
'electronic
@@ -1910,6 +1979,8 @@ FUNCTION {archive}
misc
}
+FUNCTION {article} { misc }
+
FUNCTION {book} { monograph }
FUNCTION {booklet} { book }
@@ -1938,6 +2009,8 @@ FUNCTION {inproceedings}
FUNCTION {conference} { inproceedings }
+FUNCTION {legislation} { archive }
+
FUNCTION {map}
{ "CM" set.entry.mark
misc
@@ -2248,44 +2321,26 @@ FUNCTION {presort}
'sort.key$ :=
}
-STRINGS { longest.label last.label next.extra }
+STRINGS { longest.label last.label next.extra last.extra.label }
-INTEGERS { longest.label.width last.extra.num number.label }
+INTEGERS { longest.label.width number.label }
FUNCTION {initialize.longest.label}
{ "" 'longest.label :=
#0 int.to.chr$ 'last.label :=
"" 'next.extra :=
#0 'longest.label.width :=
- #0 'last.extra.num :=
#0 'number.label :=
+ "" 'last.extra.label :=
}
FUNCTION {forward.pass}
-{ last.label short.label =
- { last.extra.num #1 + 'last.extra.num :=
- last.extra.num int.to.chr$ 'extra.label :=
- }
- { "a" chr.to.int$ 'last.extra.num :=
- "" 'extra.label :=
- short.label 'last.label :=
- }
- if$
+{
number.label #1 + 'number.label :=
}
FUNCTION {reverse.pass}
-{ next.extra "b" =
- { "a" 'extra.label := }
- 'skip$
- if$
- extra.label 'next.extra :=
- extra.label
- duplicate$ empty$
- 'skip$
- { "{\natexlab{" swap$ * "}}" * }
- if$
- 'extra.label :=
+{
label extra.label * 'label :=
}
diff --git a/macros/latex/contrib/thuthesis/thuthesis-example.pdf b/macros/latex/contrib/thuthesis/thuthesis-example.pdf
index a881f81a4a..b25df293c9 100644
--- a/macros/latex/contrib/thuthesis/thuthesis-example.pdf
+++ b/macros/latex/contrib/thuthesis/thuthesis-example.pdf
Binary files differ
diff --git a/macros/latex/contrib/thuthesis/thuthesis-example.tex b/macros/latex/contrib/thuthesis/thuthesis-example.tex
index 7e6f698ca2..39edf3af3e 100644
--- a/macros/latex/contrib/thuthesis/thuthesis-example.tex
+++ b/macros/latex/contrib/thuthesis/thuthesis-example.tex
@@ -24,6 +24,7 @@
\maketitle
% 学位论文指导小组、公开评阅人和答辩委员会名单
+% 本科生不需要
\input{data/committee}
% 使用授权的说明
@@ -39,9 +40,9 @@
% 插图和附表清单
% 本科生的插图索引和表格索引需要移至正文之后、参考文献前
-\listoffiguresandtables % 插图和附表清单
-% \listoffigures % 插图清单
-% \listoftables % 附表清单
+% \listoffiguresandtables % 插图和附表清单(仅限研究生)
+\listoffigures % 插图清单
+\listoftables % 附表清单
% 符号对照表
\input{data/denotation}
@@ -63,6 +64,7 @@
% \printbibliography % 参考文献使用 BibLaTeX 编译
% 附录
+% 本科生需要将附录放到声明之后,个人简历之前
\appendix
% \input{data/appendix-survey} % 本科生:外文资料的调研阅读报告
% \input{data/appendix-translation} % 本科生:外文资料的书面翻译
@@ -82,12 +84,15 @@
% \statement[file=scan-statement.pdf, page-style=plain]
% 个人简历、在学期间完成的相关学术成果
+% 本科生可以附个人简历,也可以不附个人简历
\input{data/resume}
% 指导教师/指导小组学术评语
+% 本科生不需要
\input{data/comments}
% 答辩委员会决议书
+% 本科生不需要
\input{data/resolution}
% 本科生的综合论文训练记录表(扫描版)
diff --git a/macros/latex/contrib/thuthesis/thuthesis-numeric.bbx b/macros/latex/contrib/thuthesis/thuthesis-numeric.bbx
index f0d6234eff..fb7dcdff68 100644
--- a/macros/latex/contrib/thuthesis/thuthesis-numeric.bbx
+++ b/macros/latex/contrib/thuthesis/thuthesis-numeric.bbx
@@ -25,3 +25,33 @@
\renewcommand*{\makelabel}[1]{\hss##1}}
{\endlist}
{\item}
+
+%
+% 重设专利title的输出,将文献类型标识符输出出去
+%
+\renewbibmacro*{patenttitle}{%原输出来自biblatex.def文件
+ \ifboolexpr{%
+ test{\iffieldundef{title}}%
+ and%
+ test{\iffieldundef{subtitle}}%
+ }%
+ {}%
+ {\printtext[title]{\bibtitlefont%
+ \printfield[titlecase]{title}%
+ \ifboolexpr{test {\iffieldundef{subtitle}}}
+ {}{\setunit{\subtitlepunct}%
+ \printfield[titlecase]{subtitle}}%
+ \iffieldundef{titleaddon}{}
+ {\setunit{\subtitlepunct}\printfield{titleaddon}}%
+ % \setunit{\subtitlepunct}\printfield{number}%写专利号
+ \setunit{\subtitlepunct}%
+ \iflistundef{location}{}
+ {\printlist{location}\setunit{\addcomma\space}}% 专利国别
+ \printfield{number}%写专利号
+ \iftoggle{bbx:gbtype}{\printfield[gbtypeflag]{usera}}{}%
+ %\iffieldundef{booktitle}{\newunit}{}%当title是析出时,不要标点
+ %\newunit
+ }%
+}%
+\clearlist{location}\clearlist{address}%
+}
diff --git a/macros/latex/contrib/thuthesis/thuthesis-numeric.bst b/macros/latex/contrib/thuthesis/thuthesis-numeric.bst
index 9f57d5ed57..0b41d73140 100644
--- a/macros/latex/contrib/thuthesis/thuthesis-numeric.bst
+++ b/macros/latex/contrib/thuthesis/thuthesis-numeric.bst
@@ -7,8 +7,8 @@
%% gbt7714.dtx (with options: `2015,thu,numerical')
%% -------------------------------------------------------------------
%% GB/T 7714—2015 BibTeX Style
-%% https://github.com/CTeX-org/gbt7714-bibtex-style
-%% Version: 2021/04/03 v2.1.1
+%% https://github.com/zepinglee/gbt7714-bibtex-style
+%% Version: 2021/12/08 v2.1.3
%% -------------------------------------------------------------------
%% Copyright (C) 2016—2021 by Zeping Lee <zepinglee AT gmail.com>
%% -------------------------------------------------------------------
@@ -29,9 +29,11 @@ INTEGERS {
terms.in.macro
year.after.author
period.after.author
+ italic.book.title
sentence.case.title
link.title
title.in.journal
+ show.patent.country
show.mark
space.before.mark
show.medium.type
@@ -43,12 +45,14 @@ INTEGERS {
show.missing.address.publisher
space.before.pages
only.start.page
+ wave.dash.in.pages
show.urldate
show.url
show.doi
show.preprint
show.note
show.english.translation
+ end.with.period
}
FUNCTION {load.config}
@@ -61,9 +65,11 @@ FUNCTION {load.config}
#0 'terms.in.macro :=
#0 'year.after.author :=
#1 'period.after.author :=
+ #0 'italic.book.title :=
#1 'sentence.case.title :=
#0 'link.title :=
#1 'title.in.journal :=
+ #1 'show.patent.country :=
#1 'show.mark :=
#0 'space.before.mark :=
#1 'show.medium.type :=
@@ -75,12 +81,14 @@ FUNCTION {load.config}
#0 'show.missing.address.publisher :=
#1 'space.before.pages :=
#0 'only.start.page :=
+ #0 'wave.dash.in.pages :=
#1 'show.urldate :=
#1 'show.url :=
#1 'show.doi :=
- #0 'show.preprint :=
+ #1 'show.preprint :=
#0 'show.note :=
#0 'show.english.translation :=
+ #1 'end.with.period :=
}
ENTRY
@@ -331,7 +339,10 @@ FUNCTION {output.check}
}
FUNCTION {fin.entry}
-{ add.period$
+{ end.with.period
+ 'add.period$
+ 'skip$
+ if$
write$
show.english.translation entry.lang lang.zh = and
{ ")"
@@ -418,10 +429,18 @@ FUNCTION {field.or.null}
if$
}
-FUNCTION {italicize}
+FUNCTION {emphasize}
{ duplicate$ empty$
{ pop$ "" }
- { "\textit{" swap$ * "}" * }
+ { "\emph{" swap$ * "}" * }
+ if$
+}
+
+FUNCTION {format.btitle}
+{ italic.book.title
+ entry.lang lang.en = and
+ 'emphasize
+ 'skip$
if$
}
@@ -556,7 +575,7 @@ FUNCTION {format.name}
{ bbl.et.al }
{ t get.str.lang 'name.lang :=
name.lang lang.en =
- { t #1 "{vv~}{ll}{~f{~}}" format.name$
+ { t #1 "{vv~}{ll}{ f{~}}" format.name$
uppercase.name
{ "u" change.case$ }
'skip$
@@ -746,7 +765,7 @@ FUNCTION {add.link}
{ url empty$ not
{ "\href{" url * "}{" * swap$ * "}" * }
{ doi empty$ not
- { "\href{http://dx.doi.org/" doi * "}{" * swap$ * "}" * }
+ { "\href{https://doi.org/" doi * "}{" * swap$ * "}" * }
'skip$
if$
}
@@ -762,7 +781,25 @@ FUNCTION {format.title}
'skip$
if$
entry.numbered number empty$ not and
- { bbl.colon * number * }
+ { bbl.colon *
+ type$ "patent" = show.patent.country and
+ { address empty$ not
+ { address * ", " * }
+ { location empty$ not
+ { location * ", " * }
+ { entry.lang lang.zh =
+ { "中国" * ", " * }
+ 'skip$
+ if$
+ }
+ if$
+ }
+ if$
+ }
+ 'skip$
+ if$
+ number *
+ }
'skip$
if$
link.title
@@ -907,6 +944,7 @@ FUNCTION {format.series.vol.num.title}
}
{ format.title.vol.num }
if$
+ format.btitle
link.title
'add.link
'skip$
@@ -938,6 +976,7 @@ FUNCTION {format.series.vol.num.booktitle}
}
{ format.booktitle.vol.num }
if$
+ format.btitle
in.booktitle
{ duplicate$ empty$ not entry.lang lang.en = and
{ "In: " swap$ * }
@@ -979,16 +1018,15 @@ FUNCTION {abbreviate}
if$
}
-FUNCTION {format.journal}
-{ ""
- short.journal
+FUNCTION {get.journal.title}
+{ short.journal
{ shortjournal empty$ not
- { shortjournal * }
+ { shortjournal }
{ journal empty$ not
- { journal * abbreviate }
+ { journal abbreviate }
{ journaltitle empty$ not
- { journaltitle * abbreviate }
- 'skip$
+ { journaltitle abbreviate }
+ { "" }
if$
}
if$
@@ -996,18 +1034,33 @@ FUNCTION {format.journal}
if$
}
{ journal empty$ not
- { journal * }
+ { journal }
{ journaltitle empty$ not
- { journaltitle * }
- 'skip$
+ { journaltitle }
+ { shortjournal empty$ not
+ { shortjournal }
+ { "" }
+ if$
+ }
if$
}
if$
}
if$
+}
+
+FUNCTION {check.arxiv.preprint}
+{ #1 #5 substring$ "l" change.case$ "arxiv" =
+ { #1 }
+ { #0 }
+ if$
+}
+
+FUNCTION {format.journal}
+{ get.journal.title
duplicate$ empty$ not
{ italic.journal entry.lang lang.en = and
- 'italicize
+ 'emphasize
'skip$
if$
}
@@ -1082,7 +1135,7 @@ FUNCTION {format.edition}
{ edition change.sentence.case 's :=
s "Revised" = s "Revised edition" = or
{ "Rev. ed." }
- { s " ed." *}
+ { s " ed." * }
if$
}
{ edition }
@@ -1272,11 +1325,16 @@ FUNCTION {format.periodical.year}
}
FUNCTION {format.date}
-{ type$ "patent" = type$ "newspaper" = or
- date empty$ not and
- { date }
- { year field.or.null
- extra.label *
+{ date empty$ not
+ { type$ "patent" = type$ "newspaper" = or
+ { date }
+ { format.year }
+ if$
+ }
+ { year empty$ not
+ { format.year }
+ { "" }
+ if$
}
if$
}
@@ -1289,9 +1347,9 @@ FUNCTION {format.editdate}
}
FUNCTION {format.urldate}
-{ urldate empty$ not
- show.urldate show.url and is.pure.electronic or and
- url empty$ not and
+{ show.urldate show.url and entry.url empty$ not and
+ is.pure.electronic or
+ urldate empty$ not and
{ "\allowbreak[" urldate * "]" * }
{ "" }
if$
@@ -1302,7 +1360,10 @@ FUNCTION {hyphenate}
""
{ t empty$ not }
{ t #1 #1 substring$ "-" =
- { "-" *
+ { wave.dash.in.pages
+ { "~" * }
+ { "-" * }
+ if$
{ t #1 #1 substring$ "-" = }
{ t #2 global.max$ substring$ 't := }
while$
@@ -1422,12 +1483,9 @@ FUNCTION {check.url}
if$
}
-FUNCTION {format.url}
-{ entry.url
-}
-
FUNCTION {output.url}
-{ entry.url empty$ not
+{ show.url is.pure.electronic or
+ entry.url empty$ not and
{ new.block
entry.url output
}
@@ -1528,9 +1586,9 @@ FUNCTION {check.electronic}
}
FUNCTION {format.eprint}
-{ eprinttype empty$ not
- { eprinttype }
- { archivePrefix empty$ not
+{ archivePrefix empty$ not
+ { archivePrefix }
+ { eprinttype empty$ not
{ archivePrefix }
{ "" }
if$
@@ -1721,7 +1779,7 @@ FUNCTION {periodical}
fin.entry
}
-FUNCTION {article}
+FUNCTION {journal.article}
{ output.bibitem
output.translation
format.authors output
@@ -1855,7 +1913,7 @@ FUNCTION {preprint}
new.block
title.in.journal
{ format.series.vol.num.title "title" output.check
- "Z" set.entry.mark
+ "A" set.entry.mark
format.mark "" output.after
new.block
}
@@ -1865,13 +1923,18 @@ FUNCTION {preprint}
new.sentence
format.edition output
new.block
- output.eprint
year.after.author not
- { format.year "year" output.check }
+ { date empty$
+ { format.date output }
+ 'skip$
+ if$
+ }
'skip$
if$
format.pages bbl.pages.colon output.after
+ format.editdate "" output.after
format.urldate "" output.after
+ output.eprint
output.url
new.block
format.note output
@@ -1879,13 +1942,19 @@ FUNCTION {preprint}
}
FUNCTION {misc}
-{ journal empty$ not
- 'article
- { booktitle empty$ not
+{ get.journal.title
+ duplicate$ empty$ not
+ { check.arxiv.preprint
+ 'preprint
+ 'journal.article
+ if$
+ }
+ { pop$
+ booktitle empty$ not
'incollection
{ publisher empty$ not
'monograph
- { eprint empty$ not show.preprint and
+ { eprint empty$ not archivePrefix empty$ not or
'preprint
{ entry.is.electronic
'electronic
@@ -1910,6 +1979,8 @@ FUNCTION {archive}
misc
}
+FUNCTION {article} { misc }
+
FUNCTION {book} { monograph }
FUNCTION {booklet} { book }
@@ -1938,6 +2009,8 @@ FUNCTION {inproceedings}
FUNCTION {conference} { inproceedings }
+FUNCTION {legislation} { archive }
+
FUNCTION {map}
{ "CM" set.entry.mark
misc
@@ -2248,44 +2321,26 @@ FUNCTION {presort}
'sort.key$ :=
}
-STRINGS { longest.label last.label next.extra }
+STRINGS { longest.label last.label next.extra last.extra.label }
-INTEGERS { longest.label.width last.extra.num number.label }
+INTEGERS { longest.label.width number.label }
FUNCTION {initialize.longest.label}
{ "" 'longest.label :=
#0 int.to.chr$ 'last.label :=
"" 'next.extra :=
#0 'longest.label.width :=
- #0 'last.extra.num :=
#0 'number.label :=
+ "" 'last.extra.label :=
}
FUNCTION {forward.pass}
-{ last.label short.label =
- { last.extra.num #1 + 'last.extra.num :=
- last.extra.num int.to.chr$ 'extra.label :=
- }
- { "a" chr.to.int$ 'last.extra.num :=
- "" 'extra.label :=
- short.label 'last.label :=
- }
- if$
+{
number.label #1 + 'number.label :=
}
FUNCTION {reverse.pass}
-{ next.extra "b" =
- { "a" 'extra.label := }
- 'skip$
- if$
- extra.label 'next.extra :=
- extra.label
- duplicate$ empty$
- 'skip$
- { "{\natexlab{" swap$ * "}}" * }
- if$
- 'extra.label :=
+{
label extra.label * 'label :=
}
diff --git a/macros/latex/contrib/thuthesis/thuthesis.dtx b/macros/latex/contrib/thuthesis/thuthesis.dtx
index 3233b5e580..f2a48c8a13 100644
--- a/macros/latex/contrib/thuthesis/thuthesis.dtx
+++ b/macros/latex/contrib/thuthesis/thuthesis.dtx
@@ -14,7 +14,7 @@
%
% \iffalse
%<*driver>
-\ProvidesFile{thuthesis.dtx}[2021/05/31 7.2.3 Tsinghua University Thesis Template]
+\ProvidesFile{thuthesis.dtx}[2022/03/19 7.2.4 Tsinghua University Thesis Template]
\documentclass{ltxdoc}
\usepackage{dtx-style}
@@ -74,10 +74,10 @@
% \item 本模板为作者根据
% 清华大学研究生院颁发的《
% \href{http://yjsy.cic.tsinghua.edu.cn/docinfo/board/boarddetail.jsp?columnId=001050603&parentColumnId=0010506&itemSeq=5365}{%
-% 研究生学位论文写作指南}》(限校内网络访问)、
+% 研究生学位论文写作指南}》(2021年6月版本,限校内网络访问)、
% 英文版《Guide to Thesis Writing for Graduate Students》、
% 清华大学教务处颁发的《
-% \href{https://lib.tsinghua.edu.cn/dra/news/annoucement/7963}{%
+% \href{https://lib.tsinghua.edu.cn/info/1073/1978.htm}{%
% 综合论文训练写作指南}》、
% 外文系的《英语专业本科生综合论文训练》和
% 清华大学《
@@ -260,7 +260,7 @@
% \end{shell}
%
% 在调用 \XeLaTeX 时,如果设置了 \option{include-spine} 选项,
-% 则需要在文件名前加上 \texttt{-shell-scape} 的命令行选项。
+% 则需要在文件名前加上 \texttt{-shell-escape} 的命令行选项。
%
% 下面的命令用来生成用户手册:
% \begin{shell}
@@ -852,10 +852,10 @@
% 可能会造成正文和公式中的数字字体不一致,需要谨慎使用。
%
% 以上字体都是 OpenType 格式的字体,需要配合
-% \href{http://mirrors.ctan.org/macros/latex/contrib/unicode-math/unicode-math.pdf}{\pkg{unicode-math}}
+% \href{http://mirrors.ctan.org/macros/unicodetex/latex/unicode-math/unicode-math.pdf}{\pkg{unicode-math}}
% 宏包使用。
% 全部数学符号的命令参考
-% \href{http://mirrors.ctan.org/macros/latex/contrib/unicode-math/unimath-symbols.pdf}{\pkg{unimath-symbols}}。
+% \href{http://mirrors.ctan.org/macros/unicodetex/latex/unicode-math/unimath-symbols.pdf}{\pkg{unimath-symbols}}。
% 注意,\pkg{unicode-math} 宏包与 \pkg{amsfonts}、\pkg{amssymb}、\pkg{bm}、
% \pkg{mathrsfs}、\pkg{upgreek} 等宏包\emph{不}兼容。
% 模板作了处理,用户可以直接使用这些宏包的命令,如 \cs{bm}、\cs{mathscr}、
@@ -1009,7 +1009,7 @@
% \end{latex}
% 另一种方式是使用 biblatex,应在导言区设置
% \begin{latex}
-% \usepackage[backend=biber,style=thuthesis-author-year]{biblatex}
+% \usepackage[style=thuthesis-author-year]{biblatex}
% \addbibresource{ref/refs.bib}
% \end{latex}
% 这里的样式由 \href{https://ctan.org/pkg/biblatex-gb7714-2015}{biblatex-gb7714-2015} 进行了少量改编,
@@ -1082,12 +1082,12 @@
% 研究生不存在空白页的问题,在编译生成声明时默认加页眉页脚(\option{plain}),
% 而插入扫描版时不再重复(\option{empty})。
%
-% 声明的页眉页脚也可以通过 \option{pagestyle} 参数手动控制,
+% 声明的页眉页脚也可以通过 \option{page-style} 参数手动控制,
% 比如编译生成时固定不加页眉页脚:
% \begin{latex}
-% \statement[page-style=plain]
+% \statement[page-style=empty]
% \end{latex}
-% 插入扫面版声明补上页眉页脚:
+% 插入扫描版声明补上页眉页脚:
% \begin{latex}
% \statement[file=scan-statement.pdf, page-style=plain]
% \end{latex}
@@ -1250,7 +1250,7 @@
% \begin{macrocode}
%<cls>\NeedsTeXFormat{LaTeX2e}[2017/04/15]
%<cls>\ProvidesClass{thuthesis}
-%<cls>[2021/05/31 7.2.3 Tsinghua University Thesis Template]
+%<cls>[2022/03/19 7.2.4 Tsinghua University Thesis Template]
% \end{macrocode}
%
% 报错
@@ -1306,7 +1306,7 @@
%<*cls>
\hyphenation{Thu-Thesis}
\def\thuthesis{ThuThesis}
-\def\version{7.2.3}
+\def\version{7.2.4}
\RequirePackage{kvdefinekeys}
\RequirePackage{kvsetkeys}
\RequirePackage{kvoptions}
@@ -1731,9 +1731,20 @@
% \end{macrocode}
%
% \pkg{pdfpages} 宏包便于我们插入扫描后的授权说明和声明页 PDF 文档。
+%
+% 由于 \pkg{pdfpages} 跟 \pkg{TikZ} 的 \pkg{external} 库冲突,
+% 需要在导言区的结尾进行处理,见
+% \href{https://github.com/tuna/thuthesis/issues/693}{\#693}。
% \begin{macrocode}
\RequirePackage{pdfpages}
\includepdfset{fitpaper=true}
+\AtEndPreamble{
+ \ifx\tikzifexternalizing\@undefined\else
+ \tikzifexternalizing{
+ \renewcommand*\includepdf[2][]{}
+ }{}
+ \fi
+}
% \end{macrocode}
%
% 更好的列表环境。
@@ -1784,9 +1795,11 @@
}
}
\AtEndOfPackageFile*{natbib}{
- \@ifpackageloaded{apacite}{}{
- \RequirePackage{bibunits}
- }
+ \ifthu@degree@bachelor
+ \@ifpackageloaded{apacite}{}{
+ \RequirePackage{bibunits}
+ }
+ \fi
}
% \end{macrocode}
%
@@ -1829,16 +1842,6 @@
\thu@package@conflict{newtxmath}{upgreek}
% \end{macrocode}
%
-% \pkg{mathtools} 需要在 \pkg{unicode-math} 前载入,
-% 参考 \url{https://tex.stackexchange.com/q/521394/82731}。
-% \begin{macrocode}
-\AtBeginOfPackageFile*{mathtools}{
- \@ifpackageloaded{unicode-math}{
- \thu@error{The "mathtools" package should be loaded before setting "math-font"}
- }{}
-}%
-% \end{macrocode}
-%
% \pkg{amsthm} 需要在 \pkg{newtx} 前载入,参考 \pkg{newtx} 的文档。
% \begin{macrocode}
\AtBeginOfPackageFile*{amsthm}{
@@ -1858,7 +1861,12 @@
% 本科生《写作指南》:
% 页边距:上:3.8 厘米,下:3.2 厘米,左右:3 厘米,装订线:左 0.2 厘米。
% 本科生 Word 模板:
-% 页眉距边界:1.5 厘米,页脚距边界:1.75 厘米。
+% 无页眉,页脚距边界:1.75 厘米。
+%
+% \pkg{fancyhdr} 的页眉是沿底部对齐的,所以只需设置 \cs{headsep},
+% \cs{headheight} 可以适当增加高度允许多行页眉。
+% 研究生:\cs{headsep} = $\SI{3}{cm} - \SI{2.2}{cm} - \SI{10.5}{bp} \times 1.3
+% \approx \SI{0.3}{cm}$。
%
% \begin{macrocode}
\geometry{
@@ -1873,8 +1881,8 @@
bottom = 3.2cm,
left = 3.2cm,
right = 3cm,
- headheight = 0.5cm,
- headsep = 1.8cm,
+ headheight = 1.9cm,
+ headsep = 1.9cm,
footskip = 1.45cm,
}%
\ifthu@output@print
@@ -1890,7 +1898,7 @@
\else
\geometry{
margin = 3cm,
- headheight = 0.5cm,
+ headheight = 2.7cm,
headsep = 0.3cm,
footskip = 0.8cm,
}%
@@ -2837,10 +2845,12 @@
\thu@set@stix@names
\setmathfont{\thu@font@name@stix@math}[
Extension = .otf,
+ Scale = MatchLowercase,
StylisticSet = \thu@xits@integral@stylistic@set,
]%
\setmathfont{\thu@font@name@stix@math}[
Extension = .otf,
+ Scale = MatchLowercase,
StylisticSet = 1,
range = {scr,bfscr},
]%
@@ -3079,6 +3089,7 @@
\@mainmattertrue
\pagenumbering{arabic}%
}
+\newif\ifthu@backmatter
\renewcommand\backmatter{%
\if@openright
\cleardoublepage
@@ -3086,6 +3097,7 @@
\clearpage
\fi
\@mainmatterfalse
+ \thu@backmattertrue
\thusetup{toc-depth = 0}%
}
% \end{macrocode}
@@ -3256,7 +3268,7 @@
% \begin{macrocode}
\newcommand\thu@circled[1]{%
\ifnum#1 >10\relax
- \thu@error{%
+ \thu@warning{%
Too many footnotes in this page.
Keep footnote less than 10%
}%
@@ -3366,8 +3378,8 @@
%
% 图表浮动体的默认位置设为 |h|。
% \begin{macrocode}
-\def\fps@figure{h}
-\def\fps@table{h}
+\def\fps@figure{htbp}
+\def\fps@table{htbp}
% \end{macrocode}
%
% 设置浮动对象和文字之间的距离
@@ -4826,41 +4838,43 @@
% 学位论文指导小组、公开评阅人和答辩委员会名单。
% \begin{macrocode}
\def\thu@committee@name{学位论文指导小组、公开评阅人和答辩委员会名单}
-\newenvironment{committee}[1][]{%
- \cleardoublepage
- \let\thu@committee@file\@empty
- \kv@define@key{thu@committee}{name}{\let\thu@committee@name\kv@value}%
- \kv@define@key{thu@committee}{file}{\let\thu@committee@file\kv@value}%
- \kv@set@family@handler{thu@committee}{%
- \ifx\kv@value\relax
- \let\thu@committee@file\kv@key
+\NewEnviron{committee}[1][]{%
+ \ifthu@degree@graduate
+ \cleardoublepage
+ \let\thu@committee@file\@empty
+ \kv@define@key{thu@committee}{name}{\let\thu@committee@name\kv@value}%
+ \kv@define@key{thu@committee}{file}{\let\thu@committee@file\kv@value}%
+ \kv@set@family@handler{thu@committee}{%
+ \ifx\kv@value\relax
+ \let\thu@committee@file\kv@key
+ \else
+ \kv@handled@false
+ \fi
+ }%
+ \kvsetkeys{thu@committee}{#1}%
+ \ifx\thu@committee@file\@empty
+ \begingroup
+ \ifthu@main@language@english
+ \ctexset{chapter/format=\centering\sffamily\fontsize{16bp}{20bp}\selectfont}
+ \fi
+ \thu@chapter*[]{\thu@committee@name}%
+ \endgroup
\else
- \kv@handled@false
+ \thu@pdfbookmark{0}{\thu@committee@name}%
+ \includepdf{\thu@committee@file}%
\fi
- }%
- \kvsetkeys{thu@committee}{#1}%
- \ifx\thu@committee@file\@empty
- \begingroup
- \ifthu@main@language@english
- \ctexset{chapter/format=\centering\sffamily\fontsize{16bp}{20bp}\selectfont}
- \fi
- \thu@chapter*[]{\thu@committee@name}%
- \endgroup
- \else
- \thu@pdfbookmark{0}{\thu@committee@name}%
- \includepdf{\thu@committee@file}%
+ \thispagestyle{empty}%
+ \ctexset{
+ section = {
+ format += {\centering},
+ numbering = false,
+ afterindent = false,
+ },
+ }%
+ \thusetup{language=chinese}
+ \BODY\clearpage
+ \thu@reset@main@language
\fi
- \thispagestyle{empty}%
- \ctexset{
- section = {
- format += {\centering},
- numbering = false,
- afterindent = false,
- },
- }%
- \thusetup{language=chinese}
-}{%
- \thu@reset@main@language
}
% \end{macrocode}
% \end{environment}
@@ -4966,7 +4980,7 @@
\centering
签\quad 名:\thu@underline[6em]{}%
导师签名:\thu@underline[6em]{}%
- 日\quad 期\thu@underline[6em]{}%
+ 日\quad 期:\thu@underline[6em]{}%
\par
\endgroup
}
@@ -5175,8 +5189,10 @@
Use "page-style" option of \protect\statement command instead%
}%
}
+\newif\ifthu@statement@exists
\newcommand\statement[1][]{%
\@mainmatterfalse
+ \thu@statement@existstrue
\ifthu@degree@bachelor
\cleardoublepage
\def\thu@statement@name{声\hspace{2em}明}%
@@ -5269,6 +5285,11 @@
% 插图清单。
% \begin{macrocode}
\renewcommand\listoffigures{%
+ \ifthu@degree@bachelor
+ \ifthu@backmatter\else
+ \thu@warning{The list of figures should be placed in back matter}%
+ \fi
+ \fi
\thu@listof{figure}%
}
\titlecontents{figure}
@@ -5284,6 +5305,11 @@
% 附表清单。
% \begin{macrocode}
\renewcommand\listoftables{%
+ \ifthu@degree@bachelor
+ \ifthu@backmatter\else
+ \thu@warning{The list of tables should be placed in back matter}%
+ \fi
+ \fi
\thu@listof{table}%
}
\titlecontents{table}
@@ -5298,11 +5324,17 @@
% 将插图和附表合在一起列出“插图和附表清单”。
% \begin{macrocode}
\newcommand\listoffiguresandtables{%
- \thu@chapter*{\thu@list@figure@table@name}%
- \@starttoc{lof}%
- \par
- \null\par
- \@starttoc{lot}%
+ \ifthu@degree@bachelor
+ \thu@warning{The list of figures and tables are for graduates only}%
+ \listoffigures
+ \listoftables
+ \else
+ \thu@chapter*{\thu@list@figure@table@name}%
+ \@starttoc{lof}%
+ \par
+ \null\par
+ \@starttoc{lot}%
+ \fi
}
% \end{macrocode}
% \end{macro}
@@ -5794,6 +5826,11 @@
% \begin{macrocode}
\g@addto@macro\appendix{%
\@mainmattertrue
+ \ifthu@degree@bachelor
+ \ifthu@statement@exists\else
+ \thu@warning{The appendices should be placed after statement}%
+ \fi
+ \fi
}
% \end{macrocode}
%
@@ -5865,6 +5902,7 @@
\thu@print@contents{survey}{l}{1}{2}{}%
\vskip 20bp%
}%
+ \let\appendix\thu@appendix@appendix
\renewcommand\bibname{参考文献}%
\let\bibsection\thu@appendix@bibsection
\renewcommand\@bibunitname{\jobname-survey}%
@@ -5907,6 +5945,7 @@
\thu@print@contents{translation}{l}{1}{2}{}%
\vskip 20bp%
}%
+ \let\appendix\thu@appendix@appendix
\def\bibsection{%
\begingroup
\ctexset{section/numbering=false}%
@@ -5969,6 +6008,16 @@
}
% \end{macrocode}
%
+% 书面翻译的附录。
+% \begin{macrocode}
+\newcommand\thu@appendix@appendix{%
+ \def\theHsection{\Hy@AlphNoErr{section}}%
+ \setcounter{section}{0}%
+ \setcounter{subsection}{0}%
+ \renewcommand\thesection{\thechapter.\@Alph\c@section}%
+}%
+% \end{macrocode}
+%
% 调研阅读报告的参考文献(或书面翻译对应的外文资料的原文索引)标题用宋体小四号字,段前 20pt,段后 6pt,行距 20pt。
% \begin{macrocode}
\newcommand\thu@appendix@bibsection{%
@@ -6061,19 +6110,21 @@
% \subsection{指导教师/小组学术评语}
% \begin{environment}{comments}
% \begin{macrocode}
-\newenvironment{comments}[1][]{%
- \@mainmatterfalse
- \kv@define@key{thu@comments}{name}{\let\thu@comments@name\kv@value}%
- \kv@set@family@handler{thu@comments}{%
- \ifx\kv@value\relax
- \let\thu@comments@name\kv@key
- \else
- \kv@handled@false
- \fi
- }%
- \kvsetkeys{thu@comments}{#1}%
- \chapter{\thu@comments@name}%
-}{%
+\NewEnviron{comments}[1][]{%
+ \ifthu@degree@graduate
+ \@mainmatterfalse
+ \kv@define@key{thu@comments}{name}{\let\thu@comments@name\kv@value}%
+ \kv@set@family@handler{thu@comments}{%
+ \ifx\kv@value\relax
+ \let\thu@comments@name\kv@key
+ \else
+ \kv@handled@false
+ \fi
+ }%
+ \kvsetkeys{thu@comments}{#1}%
+ \chapter{\thu@comments@name}%
+ \BODY\clearpage
+ \fi
}
% \end{macrocode}
% \end{environment}
@@ -6081,10 +6132,13 @@
% \subsection{答辩委员会决议书}
% \begin{environment}{resolution}
% \begin{macrocode}
-\newenvironment{resolution}{%
- \@mainmatterfalse
- \chapter{\thu@resolution@name}%
-}{}
+\NewEnviron{resolution}{%
+ \ifthu@degree@graduate
+ \@mainmatterfalse
+ \chapter{\thu@resolution@name}%
+ \BODY\clearpage
+ \fi
+}
% \end{macrocode}
% \end{environment}
%
@@ -6150,6 +6204,7 @@
\pdfstringdefDisableCommands{
\let\\\relax
\let\quad\relax
+ \let\qquad\relax
\let\hspace\@gobble
}%
% \end{macrocode}
@@ -6195,6 +6250,20 @@
}
% \end{macrocode}
%
+% \subsubsection{\pkg{mathtools} 宏包}
+%
+% \pkg{mathtools} 会修改 \pkg{unicode-math} 的 \cs{underbrace} 和 \cs{overbrace},
+% 需要还原为 \cs{LaTeXunderbrace} 和 \cs{LaTeXoverbrace},
+% 参考 \url{https://tex.stackexchange.com/q/521394/82731}。
+% \begin{macrocode}
+\AtEndOfPackageFile*{mathtools}{
+ \@ifpackageloaded{unicode-math}{
+ \let\underbrace\LaTeXunderbrace
+ \let\overbrace\LaTeXoverbrace
+ }{}
+}
+% \end{macrocode}
+%
% \subsubsection{\pkg{nomencl} 宏包}
%
% \begin{macrocode}
@@ -6209,11 +6278,6 @@
%
% \begin{macrocode}
\AtEndOfPackageFile*{siunitx}{%
- \sisetup{
- group-minimum-digits = 4,
- separate-uncertainty = true,
- inter-unit-product = \ensuremath{{}\cdot{}},
- }
\newcommand\thu@set@siunitx@language{%
\ifthu@language@chinese
\sisetup{
@@ -6526,7 +6590,12 @@
\RequirePackage{enumitem}
\RequirePackage{etoolbox}
\RequirePackage{metalogo}
+
+% Pretending the `amssymb` has been loaded.
+% This should be removed after `markdown` v2.13.0.
+\expandafter\def\csname ver@amssymb.sty\endcsname{0000/00/00}
\RequirePackage[tightLists=false]{markdown}
+\expandafter\let\csname ver@amssymb.sty\endcsname\relax
\markdownSetup{
renderers = {
diff --git a/macros/latex/contrib/thuthesis/thuthesis.pdf b/macros/latex/contrib/thuthesis/thuthesis.pdf
index 6925a82705..ad3acc14f2 100644
--- a/macros/latex/contrib/thuthesis/thuthesis.pdf
+++ b/macros/latex/contrib/thuthesis/thuthesis.pdf
Binary files differ