% \iffalse meta-comment
%
% File: ctex-kernel.dtx
% -----------------------------------------------------------------------
%   Copyright (C) 2003--2026
%   CTEX.ORG and any individual authors listed elsewhere in this file.
% -----------------------------------------------------------------------
%   This work may be distributed and/or modified under the conditions   *
%   of the LaTeX Project Public License (LPPL), either version 1.3c of  *
%   this license or (at your option) any later version.                 *
%   The latest version of this license is in                            *
%                                                                       *
%       http://www.latex-project.org/lppl.txt                           *
%                                                                       *
%   and version 1.3c or later is part of all distributions of LaTeX     *
%   version 2008 or later.                                              *
%                                                                       *
%   This work has the LPPL maintenance status `maintained'.             *
% -----------------------------------------------------------------------
%   This work consists of the files ctex.dtx,                           *
%                                   ctex-kernel.dtx,                    *
%                                   ctex-engine.dtx,                    *
%                                   ctex-scheme.dtx,                    *
%                                   ctex-auxpkg.dtx,                    *
%                                   ctex-fontset.dtx,                   *
%                                   ctexpunct.spa,                      *
%                                   ctxdoc.cls,                         *
%                                   ctxdocstrip.tex,                    *
%                                   ctex-zhconv.lua,                    *
%                                   ctex-zhconv-index.lua,              *
%                                   ctex-zhconv-make.lua,               *
%                 the derived files ctex.ins,                           *
%                                   ctex.sty,                           *
%                                   ctexsize.sty,                       *
%                                   ctexheading.sty,                    *
%                                   ctexart.cls,                        *
%                                   ctexbook.cls,                       *
%                                   ctexrep.cls,                        *
%                                   ctexbeamer.cls,                     *
%                                   ctexcap.sty,                        *
%                                   ctexhook.sty,                       *
%                                   ctexpatch.sty,                      *
%                                   ctex-c5size.clo,                    *
%                                   ctex-cs4size.clo,                   *
%                                   ctex-heading-article.def,           *
%                                   ctex-heading-book.def,              *
%                                   ctex-heading-report.def,            *
%                                   ctex-heading-beamer.def,            *
%                                   ctexbackend.cfg,                    *
%                                   ctex-engine-pdftex.def,             *
%                                   ctex-engine-xetex.def,              *
%                                   ctex-engine-luatex.def,             *
%                                   ctex-engine-aptex.def,              *
%                                   ctex-engine-uptex.def,              *
%                                   ctex-name-utf8.cfg,                 *
%                                   ctex-name-gbk.cfg,                  *
%                                   ctex.cfg,                           *
%                                   ctexopts.cfg,                       *
%                                   ctex-scheme-plain.def,              *
%                                   ctex-scheme-plain-article.def,      *
%                                   ctex-scheme-plain-book.def,         *
%                                   ctex-scheme-plain-report.def,       *
%                                   ctex-scheme-plain-beamer.def,       *
%                                   ctex-scheme-chinese.def,            *
%                                   ctex-scheme-chinese-article.def,    *
%                                   ctex-scheme-chinese-book.def,       *
%                                   ctex-scheme-chinese-report.def,     *
%                                   ctex-scheme-chinese-beamer.def,     *
%                                   ctex-fontset-adobe.def,             *
%                                   ctex-fontset-fandol.def,            *
%                                   ctex-fontset-founder.def,           *
%                                   ctex-fontset-hanyi.def,             *
%                                   ctex-fontset-mac.def,               *
%                                   ctex-fontset-macnew.def,            *
%                                   ctex-fontset-macold.def,            *
%                                   ctex-fontset-ubuntu.def,            *
%                                   ctex-fontset-windows.def,           *
%                                   c19rm.fd,                           *
%                                   c19sf.fd,                           *
%                                   c19tt.fd,                           *
%                                   c70rm.fd,                           *
%                                   c70sf.fd,                           *
%                                   c70tt.fd,                           *
%                                   jy2zhrm.fd,                         *
%                                   jy2zhsf.fd,                         *
%                                   jy2zhtt.fd,                         *
%                                   jt2zhrm.fd,                         *
%                                   jt2zhsf.fd,                         *
%                                   jt2zhtt.fd,                         *
%                                   ctexspa.def,                        *
%                     translator-theorem-dictionary-ChineseUTF8.dict,   *
%                     translator-theorem-dictionary-ChineseGBK.dict,    *
%                                   ctex-spa-make.tex,                  *
%                                   ctex-spa-macro.tex,                 *
%                                   ctex-zhmap-adobe.tex,               *
%                                   ctex-zhmap-fandol.tex,              *
%                                   ctex-zhmap-founder.tex,             *
%                                   ctex-zhmap-hanyi.tex,               *
%                                   ctex-zhmap-mac.tex,                 *
%                                   ctex-zhmap-ubuntu.tex,              *
%                                   ctex-zhmap-windows.tex,             *
%           the documentation files ctex.pdf,                           *
%                               and README.md.                          *
% -----------------------------------------------------------------------
%                                                                       *
%   Any modification of this file should ensure that the copyright and  *
%   license information is placed in the derived files.                 *
%                                                                       *
% -----------------------------------------------------------------------
%
%<*!driver>
%<class|style>\NeedsTeXFormat{LaTeX2e}[2026/06/01]
%<class>\input{ctexbackend.cfg}
%<class|style>\RequirePackage{expl3}
%<+!driver>\GetIdInfo $Id: ctex-kernel.dtx 2.6.3 2026-07-08 18:13:24 +0800 8c6212ee Mingyu Hsia <myhsia@outlook.com>$
%<ctex>  {Chinese adapter in LaTeX (CTEX)}
%<ctex>\ProvidesExplPackage{ctex}
%<ctexsize>  {Chinese font size definition (CTEX)}
%<ctexsize>\ProvidesExplPackage{ctexsize}
%<ctexheading>  {Heading style modification (CTEX)}
%<ctexheading>\ProvidesExplPackage{ctexheading}
%<class&article>  {Chinese adapter for class article (CTEX)}
%<class&article>\ProvidesExplClass{ctexart}
%<class&book>  {Chinese adapter for class book (CTEX)}
%<class&book>\ProvidesExplClass{ctexbook}
%<class&report>  {Chinese adapter for class report (CTEX)}
%<class&report>\ProvidesExplClass{ctexrep}
%<class&beamer>  {Chinese adapter for class beamer (CTEX)}
%<class&beamer>\ProvidesExplClass{ctexbeamer}
%<c5size>  {c5size option (CTEX)}
%<c5size>\ProvidesExplFile{ctex-c5size.clo}
%<cs4size>  {cs4size option (CTEX)}
%<cs4size>\ProvidesExplFile{ctex-cs4size.clo}
%<heading&article>  {Heading modification for article (CTEX)}
%<heading&article>\ProvidesExplFile{ctex-heading-article.def}
%<heading&book>  {Heading modification for book (CTEX)}
%<heading&book>\ProvidesExplFile{ctex-heading-book.def}
%<heading&report>  {Heading modification for report (CTEX)}
%<heading&report>\ProvidesExplFile{ctex-heading-report.def}
%<heading&beamer>  {Heading modification for beamer (CTEX)}
%<heading&beamer>\ProvidesExplFile{ctex-heading-beamer.def}
%<!driver>  {\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
%</!driver>
%
% \fi
%
% \begin{implementation}
%
% \paragraph*{\fbox{\file{\jobname-kernel.dtx}}}
%
%    \begin{macrocode}
%<@@=ctex>
%    \end{macrocode}
%
% \changes{v2.6.2}{2026/07/02}{订正 \file{ctex-heading-*.def} 中
%   \cs{ProvidesExplFile} 使用与实际文件名不匹配的 \file{ctex-*.def}。}
% \changes{v2.5.9}{2022/05/27}{设置消息模块的名字和类型。}
% \changes{v2.5.10}{2022/06/10}{更新一些内部函数。}
% \changes{v2.5.10}{2022/07/08}{不直接依赖 \pkg{xparse} 和 \pkg{l3keys2e}。}
%
%    \begin{macrocode}
%<*class|style>
\cs_if_exist:NF \NewDocumentCommand
  { \RequirePackage { xparse } }
%<class>\prop_gput:Nnn \g_msg_module_type_prop { ctex } { Class }
%<article>\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexart }
%<book>\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexbook }
%<report>\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexrep }
%<beamer>\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexbeamer }
%<ctexsize>\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexsize }
%<ctexheading>\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexheading }
%</class|style>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*class|ctex>
%    \end{macrocode}
%
% \changes{v2.3}{2015/12/20}{与 \LaTeXiii{} (2015/12/20) 同步。}
% \changes{v2.4.10}{2017/07/19}{常数 \cs{c_minus_one} 已过时。}
% \changes{v2.4.10}{2017/07/22}{使用 \texttt{lazy} 函数对 Boolean 表达式
% 进行最小化运算（\LaTeXiii{} 2017/07/19）。}
% \changes{v2.6.0}{2024/04/20}{提升 \LaTeXiii{} 版本至 2022/10/09。}
% \changes{v2.6.0}{2026/05/03}{提升 \LaTeXiii{} 最低版本要求至 2025/10/09。}
%
% 检查 \pkg{expl3} 的版本。
%    \begin{macrocode}
\msg_new:nnnn { ctex } { l3-too-old }
  { Support~package~`#1'~too~old. }
  {
    Please~update~an~up-to-date~version~of~the~bundles\\\\
    `l3kernel'~and~`l3packages'\\\\
    using~your~TeX~package~manager~or~from~CTAN.
  }
\@ifpackagelater { expl3 } { 2025/10/09 } { }
  { \msg_error:nnn { ctex } { l3-too-old } { expl3 } }
%    \end{macrocode}
%
% \begin{variable}{\c_@@_engine_str,\c_@@_engine_file_str}
% 引擎检查。目前 \LaTeXiii{} 将 \ApTeX{} 识别为 \upTeX。
%    \begin{macrocode}
\str_const:Ne \c_@@_engine_str
  { \cs_if_exist:NTF \ngostype { aptex } { \c_sys_engine_str } }
\msg_new:nnnn { ctex } { engine-not-supported }
  { Engine~`#1'~is~not~yet~supported,~ctex~will~abort! }
  { You~can~switch~to~xelatex,~lualatex,~pdflatex,~uplatex,~or~aplatex. }
\file_if_exist:nTF { ctex-engine- \c_@@_engine_str .def }
  {
    \str_const:Ne \c_@@_engine_file_str
      { ctex-engine- \c_@@_engine_str .def }
  }
  { \msg_critical:nne { ctex } { engine-not-supported } { \c_@@_engine_str } }
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
%</class|ctex>
%    \end{macrocode}
%
% \changes{v2.5}{2020/04/19}
%   {处理 \cs{ctex_file_input:n} 在 \pkg{ctexsize} 中未定义的错误。}
% \changes{v2.5}{2020/04/21}{在 \pkg{ctexsize} 也载入 \pkg{fix-cm}。}
%
%    \begin{macrocode}
%<*class|ctex|ctexheading|ctexsize>
%    \end{macrocode}
%
% \pkg{ctexsize} 也要载入 \pkg{fix-cm} 包解决传统 cm 字体字号缺失的问题。
%    \begin{macrocode}
%<!ctexsize>\RequirePackage { ctexhook , ctexpatch }
%<!ctexheading>\RequirePackage { fix-cm }
%    \end{macrocode}
%
% 宏包载入检查。
%    \begin{macrocode}
%<*class|ctex>
%<*class>
\ctex_disable_package:n { ctex }
\ctex_disable_package:n { ctexcap }
%</class>
\ctex_disable_package:n { ctexsize }
\ctex_disable_package:n { ctexheading }
%</class|ctex>
%    \end{macrocode}
%
% \changes{v2.5.7}{2021/06/04}{兼容 \LaTeX \ 2021/06/01 的字体钩子。}
%
% \begin{variable}{\c_@@_everysel_loaded_bool}
% \LaTeX \ 2021-06-01 以后的版本内建了 \pkg{everysel} 包的功能。
%    \begin{macrocode}
%<*!ctexsize>
%<*!ctexheading>
\ctex_if_format_at_least:nTF { 2021/06/01 }
  { \bool_const:Nn \c_@@_everysel_loaded_bool { \c_false_bool } }
  {
    \RequirePackage { everysel }
    \bool_const:Nn \c_@@_everysel_loaded_bool { \c_true_bool }
  }
%</!ctexheading>
%    \end{macrocode}
% \end{variable}
%
% \subsection{内部函数与变量}
%
% \begin{variable}{\l_@@_tmp_tl,\l_@@_tmp_int,\l_@@_tmp_box,\l_@@_tmp_dim}
% 临时变量。
%    \begin{macrocode}
\tl_clear_new:N \l_@@_tmp_tl
\int_new:N \l_@@_tmp_int
\box_new:N \l_@@_tmp_box
%<!ctexheading>\dim_new:N \l_@@_tmp_dim
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[int]{\ctex_define_option:n,
% \ctex_define:n,\ctex_set:n,\ctex_set:nn}
% 在宏包内部使用的键值选项定义、设置命令。
%    \begin{macrocode}
%</!ctexsize>
\cs_new_protected:Npn \ctex_define_option:n
  { \keys_define:nn { ctex / option } }
%<*!ctexsize>
\cs_new_protected:Npn \ctex_define:n
  { \keys_define:nn { ctex } }
\cs_new_protected:Npn \ctex_set:n
  { \keys_set:nn { ctex } }
\cs_new_protected:Npn \ctex_set:nn #1
  { \keys_set:nn { ctex / #1 } }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.3}{2020/06/06}{正确关闭和恢复 \LaTeXiii 语法环境。}
% \changes{v2.5.4}{2020/08/02}{应用 \pkg{l3cctab}。}
% \changes{v2.5.5}{2020/10/17}{放弃应用 \pkg{l3cctab}。}
%
% \begin{macro}[int]{\ctex_scheme_input:n}
% 输入 \opt{scheme} 文件。先查找当前文档类下的 \meta{scheme}，找不到再查找一般的文件。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_scheme_input:n #1
  {
    \ctex_push_file:
      \tl_if_exist:NTF \c_@@_class_tl
        {
          \file_if_exist_input:nF { ctex-scheme- #1 - \c_@@_class_tl .def }
            { \file_input:n  { ctex-scheme- #1 .def } }
        }
        { \file_input:n  { ctex-scheme- #1 .def } }
    \ctex_pop_file:
  }
\cs_generate_variant:Nn \ctex_scheme_input:n { o }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\g_@@_section_depth_int}
% 若大于 |3|，则 \tn{paragraph} 和 \tn{subparagraph} 标题单独占一行；若为 |3|，则
% \tn{paragraph} 单独占一行。
%    \begin{macrocode}
%<*!beamer>
\int_new:N \g_@@_section_depth_int
\int_gset:Nn \g_@@_section_depth_int { 2 }
%</!beamer>
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
%</!ctexsize>
%</class|ctex|ctexheading|ctexsize>
%<*class|ctex>
%    \end{macrocode}
%
% 对旧版本的宏包给出错误信息。
%    \begin{macrocode}
\msg_new:nnnn { ctex } { package-too-old }
  { Support~package~`#1'~too~old. }
  {
    Please~update~an~up-to-date~version~of~the~package~`#1'\\
    using~your~TeX~package~manager~or~from~CTAN.
  }
%    \end{macrocode}
%
% \changes{v2.1}{2015/05/25}{不依赖 \pkg{ifpdf} 宏包。}
%
% \begin{macro}[int]{\ifctexpdf}
% 在 \pkg{zhmetrics} 映射文件中使用。
%    \begin{macrocode}
\sys_if_output_pdf:TF
  { \cs_new_eq:NN \ifctexpdf \if_true: }
  { \cs_new_eq:NN \ifctexpdf \if_false: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_if_preamble:TF}
% 测试是否在 \LaTeXe{} 的导言区。在宏包内部初始为真，文档最开始位置再设置为假。
% 注意，钩子 \cs{ctex_after_end_preamble:n} 在 \tn{AtBeginDocument} 之后执行，
% 可以与 \tn{@onlypreamble} 的行为一致。
%    \begin{macrocode}
\cs_new_eq:NN \ctex_if_preamble:TF \use_i:nn
\ctex_after_end_preamble:n { \cs_set_eq:NN \ctex_if_preamble:TF \use_ii:nn }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.3}{2015/09/17}{代码实现避免使用 \tn{lowercase} 技巧（Joseph Wright）。}
%
% \changes{v2.4.16}{2019/05/11}{允许设置 \texttt{autoindent} 为 $0$。}
%
% \begin{macro}[int]{\ctex_set_default_ccwd:Nn}
% 若参数 |#2| 带长度单位，则设置它为 |tl| 变量 |#1| 的值，否则以 \tn{ccwd} 为单位。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_set_default_ccwd:Nn #1#2
  { \tl_set:Ne #1 { \@@_default_ccwd_aux:n {#2} } }
\cs_new:Npn \@@_default_ccwd_aux:n #1
  {
    \exp_not:n {#1}
    \exp_after:wN \@@_default_ccwd_aux:w
      \dim_use:N \tex_dimexpr:D #1 pt \scan_stop: \q_stop
  }
\exp_last_unbraced:NNNNo
  \cs_new:Npn \@@_default_ccwd_aux:w #1 { \tl_to_str:n { pt } } #2 \q_stop
    { \tl_if_empty:nT {#2} { \ccwd } }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\g_@@_encoding_tl}
% 所有引擎下默认编码均设为 UTF-8，初始值为空，\tn{ProcessKeysOptions} 再判断。
%    \begin{macrocode}
\tl_new:N \g_@@_encoding_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_zhmCJK_bool}
% 是否使用 \pkg{zhmCJK} 宏包。
%    \begin{macrocode}
\bool_new:N \g_@@_zhmCJK_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_autoindent_tl}
% 保存 \opt{autoindent} 选项的值，空值表示不自动调整首行缩进。
%    \begin{macrocode}
\tl_new:N \l_@@_autoindent_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[int]{\ctex_if_autoindent_touched:F}
% 检查 \opt{autoindent} 选项是否被用户设置。
%    \begin{macrocode}
\cs_new_eq:NN \ctex_if_autoindent_touched:F \use:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_zhmap_case:nnn}
% 参数 |#1| 是 \pkg{zhmCJK} 的内容，|#2| 是 \pkg{zhmetrics}。
%    \begin{macrocode}
\cs_new_eq:NN \ctex_zhmap_case:nnn \use_ii:nnn
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_at_end:n}
% 区分 \tn{AtEndOfClass} 和 \tn{AtEndOfPackage}，虽然它们的意思都是一样的。
%    \begin{macrocode}
%<class>\cs_new_protected:Npn \ctex_at_end:n { \AtEndOfClass }
%<ctex>\cs_new_protected:Npn \ctex_at_end:n { \AtEndOfPackage }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\ctex_load_std_class:n,\g_@@_std_options_clist}
% 保存传递给标准文档类的选项。
% 使用 \tn{PassOptionsToClass} 是为了预防可能存在的选项冲突，选项列表展开后再传递。
%    \begin{macrocode}
%<*class>
\cs_new_protected:Npn \ctex_load_std_class:n #1
  {
    \tl_const:Nn \c_@@_class_tl {#1}
    \exp_args:No \PassOptionsToClass
      { \g_@@_std_options_clist }
      {#1}
    \LoadClass {#1}
  }
\clist_new:N \g_@@_std_options_clist
%</class>
%    \end{macrocode}
% \end{variable}
%
% 对无效选项给出警告。
% \changes{v2.6.0}{2026/05/02}{使用 \cs{l_keys_key_str} 和
%   \cs{l_keys_choice_str} 替代已废弃的 \texttt{\_tl} 版本（\#806）。}
%    \begin{macrocode}
\msg_new:nnn { ctex } { invalid-option }
  { Option~`\l_keys_key_str'~is~invalid~in~current~mode. }
\msg_new:nnn { ctex } { invalid-value }
  { Value~`#1'~is~invalid~for~the~key~`\l_keys_key_str'. }
\msg_new:nnn { ctex } { CJKecglue-unsupported }
  { `experiment/CJKecglue'~is~not~supported~by~the~current~engine. }
%    \end{macrocode}
%
% \begin{macro}[int]{\ctex_deprecated_option:nn,
% \ctex_set_deprecated_option:n,\ctex_deprecated_command:Nn}
% 对过时选项或命令给出警告。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_deprecated_option:n
  { \msg_warning:nnn { ctex } { deprecated-option } }
\cs_new_protected:Npn \ctex_set_deprecated_option:n #1
  {
    \ctex_deprecated_option:n { Option~`#1'~is~set. }
    \ctex_set:nn { option } {#1}
  }
\cs_new_protected:Npn \ctex_deprecated_command:Nn #1#2
  {
    \msg_warning:nnee { ctex } { deprecated-command }
      { \token_to_str:N #1 } { \exp_not:n {#2} }
  }
\msg_new:nnn { ctex } { deprecated-option }
  { Option~`\l_keys_key_str'~is~deprecated.\\ #1 }
\msg_new:nnn { ctex } { deprecated-command }
  { Command~`#1'~is~deprecated.\\ #2 }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</class|ctex>
%    \end{macrocode}
%
% \begin{variable}{\g_@@_font_size_int}
% |0| 表示修改默认字体大小为五号，|1| 为小四号，大于 1 则不作修改。初始值 |-1|
% 表示 \opt{zihao} 选项未初始化，会在将来根据文档类决定初值。
%    \begin{macrocode}
%<*class|ctex|ctexsize>
\int_new:N \g_@@_font_size_int
\int_gset:Nn \g_@@_font_size_int { -1 }
%</class|ctex|ctexsize>
%    \end{macrocode}
% \end{variable}
%
% \subsection{宏包选项}
%
% \changes{v2.3}{2015/09/25}
%   {\texttt{.value_required:} 和 \texttt{.value_forbidden:} 已过时。}
%
%    \begin{macrocode}
%<*class|style>
\ctex_define_option:n
  {
%</class|style>
%    \end{macrocode}
%
% \changes{v2.6.0}{2026/05/04}{新增实验性
%   \opt{experiment/font-size-system} 选项（\#543）。}
% \changes{v2.6.0}{2026/05/04}{将 \opt{experiment/font-size-system}
%   的 \opt{traditional} 选项更名为 \opt{letterpress}（\#813）。}
% \changes{v2.6.0}{2026/06/23}{文档：在标准字体命令、中文字号表附近提示
%   \opt{experiment/font-size-system} 的影响；说明
%   \opt{letterpress} 只是金属活字排印字号体系之一（\#871）。}
%
% \begin{macro}{experiment/font-size-system}
% 选择字号系统。预设有 |word| 和 |letterpress| 两种字号系统，用户也可以自定义。
%    \begin{macrocode}
%<*class|ctex|ctexsize>
    experiment / font-size-system .tl_gset:N = \g_@@_font_size_system_tl ,
    experiment / font-size-system .initial:n = { word } ,
    experiment / font-size-system .value_required:n = true ,
%</class|ctex|ctexsize>
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2015/05/06}{新增 \opt{zihao} 选项。}
% \changes{v2.0}{2015/05/06}{\opt{c5size}, \opt{cs4size} 是过时选项。}
%
% \begin{macro}{zihao}
% \changes{v2.4.1}{2016/05/13}{不允许无参 \opt{zihao} 选项。}
%    \begin{macrocode}
%<*class|ctex|ctexsize>
    zihao .choice: ,
    zihao .value_required:n = true ,
    zihao /     5  .code:n = { \int_gset:Nn \g_@@_font_size_int { 0 } } ,
    zihao /    -4  .code:n = { \int_gset:Nn \g_@@_font_size_int { 1 } } ,
    zihao / false  .code:n = { \int_gset:Nn \g_@@_font_size_int { 2 } } ,
%<ctexsize>  }
%</class|ctex|ctexsize>
%<*class|ctex>
    c5size  .code:n = { \ctex_set_deprecated_option:n { zihao =  5 } } ,
    cs4size .code:n = { \ctex_set_deprecated_option:n { zihao = -4 } } ,
    c5size  .value_forbidden:n = true ,
    cs4size .value_forbidden:n = true ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/04/23}{新增 \opt{linespread} 选项。}
%
% \begin{macro}{linespread}
% 行距初始值为标志 \texttt{nan}，用于检查用户是否设置了 \opt{linespread} 选项。
%    \begin{macrocode}
    linespread  .fp_set:N = \l_@@_line_spread_fp ,
    linespread .initial:n = { \c_nan_fp } ,
    linespread .value_required:n = true ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/13}{新增 \opt{autoindent} 选项。}
%
% \begin{macro}{autoindent}
% 自动调整段落的首行缩进功能。
%    \begin{macrocode}
    autoindent .choice: ,
    autoindent .default:n = { true } ,
    autoindent / true    .code:n =
      {
        \tl_set:Nn \l_@@_autoindent_tl { 2 \ccwd }
        \cs_set_eq:NN \ctex_if_autoindent_touched:F \use_none:n
      } ,
    autoindent / false   .code:n =
      {
        \tl_clear:N \l_@@_autoindent_tl
        \cs_set_eq:NN \ctex_if_autoindent_touched:F \use_none:n
      } ,
    autoindent / unknown .code:n =
      {
        \ctex_set_default_ccwd:Nn \l_@@_autoindent_tl {#1}
        \cs_set_eq:NN \ctex_if_autoindent_touched:F \use_none:n
      } ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2015/03/21}{\opt{indent}, \opt{noindent} 是过时选项。}
% \begin{macro}{indent}
% 仅为兼容性保留，已过时。
%    \begin{macrocode}
    indent .code:n =
      {
        \ctex_deprecated_option:n
          {
            The~functionality~has~been~removed.\\
            It's~better~to~set~the~heading~styles~via~`afterindent'~option.
          }
      } ,
    indent .value_forbidden:n = true ,
    noindent .code:n =
      {
        \ctex_deprecated_option:n
          {
            The~functionality~has~been~removed.\\
            It's~better~to~set~the~heading~styles~via~`afterindent'~option.
          }
      } ,
    noindent .value_forbidden:n = true ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5}{2019/11/10}{所有引擎下默认编码均设为 UTF-8。}
%
% \begin{macro}{GBK,UTF8}
% 文档编码，默认为 UTF-8。
%    \begin{macrocode}
    GBK  .code:n =
      {
        \sys_if_engine_pdftex:TF
          { \tl_gset:Nn \g_@@_encoding_tl { GBK } }
          {
            \msg_warning:nn { ctex } { invalid-option }
            \tl_gset:Nn \g_@@_encoding_tl { UTF8 }
          }
      } ,
    UTF8 .code:n = { \tl_gset:Nn \g_@@_encoding_tl { UTF8 } } ,
    GBK  .value_forbidden:n = true ,
    UTF8 .value_forbidden:n = true ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/08}{新增 \opt{fontset} 选项。}
% \changes{v2.0}{2015/03/21}{\opt{nofonts}, \opt{adobefonts}, \opt{winfonts}
% 是过时选项。}
%
% \begin{macro}{fontset}
% 初始值为空。若用户未指定，则根据操作系统载入对应字体配置，可以区分 Windows、
% macOS 和其他。
%    \begin{macrocode}
    fontset    .tl_gset:N = \g_@@_fontset_tl ,
    nofonts    .code:n = { \ctex_set_deprecated_option:n { fontset = none } } ,
    adobefonts .code:n = { \ctex_set_deprecated_option:n { fontset = adobe } } ,
    winfonts   .code:n = { \ctex_set_deprecated_option:n { fontset = windows } } ,
    nofonts    .value_forbidden:n = true ,
    winfonts   .value_forbidden:n = true ,
    adobefonts .value_forbidden:n = true ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/08}{新增 \opt{zhmCJK} 支持选项。}
% \changes{v2.0}{2015/03/22}{\opt{nozhmap} 是过时选项。}
%
% \begin{macro}{zhmap}
%    \begin{macrocode}
    zhmap .choice: ,
    zhmap .default:n = { true } ,
    zhmap / zhmCJK .code:n =
      {
        \bool_gset_true:N \g_@@_zhmCJK_bool
        \cs_gset_eq:NN \ctex_zhmap_case:nnn \use_i:nnn
      } ,
    zhmap / true   .code:n =
      {
        \bool_gset_false:N \g_@@_zhmCJK_bool
        \cs_gset_eq:NN \ctex_zhmap_case:nnn \use_ii:nnn
      } ,
    zhmap / false  .code:n =
      {
        \bool_gset_false:N \g_@@_zhmCJK_bool
        \cs_gset_eq:NN \ctex_zhmap_case:nnn \use_iii:nnn
      } ,
    nozhmap   .code:n =
      { \ctex_set_deprecated_option:n { zhmap = false } } ,
    nozhmap   .value_forbidden:n = true ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/04/11}{\opt{punct} 选项可以设置标点格式。}
% \changes{v2.0}{2015/03/21}{\opt{nopunct} 是过时选项。}
%
% \begin{macro}{punct}
% 设置标点符号输出格式。
%    \begin{macrocode}
    punct   .tl_set:N = \l_@@_punct_tl ,
    punct  .default:n = { quanjiao } ,
    punct  .initial:n = { quanjiao } ,
    nopunct   .code:n = \ctex_set_deprecated_option:n { punct = plain } ,
    nopunct   .value_forbidden:n = true ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2015/03/22}{\opt{nospace} 是过时选项。}
% \begin{macro}{space}
%    \begin{macrocode}
    space .choices:nn =
      { true , auto , false }
      { \ctex_at_end:n { \ctex_set:n { space = #1 } } } ,
    space  .default:n = { true } ,
    nospace   .code:n = { \ctex_deprecated_option:nn { space = false } } ,
    nospace   .value_forbidden:n = true ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/08}{\pkg{ctex} 宏包新增 \opt{heading} 选项。}
%
% \begin{macro}{heading}
%    \begin{macrocode}
    heading .bool_set:N = \l_@@_heading_bool ,
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</class|ctex>
%<*class|ctex|ctexheading>
%    \end{macrocode}
%
% \begin{macro}{sub3section,sub4section}
% \begin{macrocode}
%<*!beamer>
    sub3section .code:n =
      { \int_gset:Nn \g_@@_section_depth_int { 3 } } ,
    sub4section .code:n =
      { \int_gset:Nn \g_@@_section_depth_int { 4 } } ,
    sub3section .value_forbidden:n = true ,
    sub4section .value_forbidden:n = true ,
%</!beamer>
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2015/04/15}{新增 \opt{scheme} 选项，并将 \opt{cap} 和 \opt{nocap}
% 列为过时选项。}
%
% \begin{macro}{scheme}
%    \begin{macrocode}
    scheme .tl_set:N  = \l_@@_scheme_tl ,
%<*ctexheading>
    scheme .default:n = { plain } ,
    scheme .initial:n = { plain }
  }
%</ctexheading>
%<*!ctexheading>
    scheme .default:n = { chinese } ,
    scheme .initial:n = { chinese } ,
%</!ctexheading>
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</class|ctex|ctexheading>
%<*class|ctex>
%    \end{macrocode}
%
% \begin{macro}{cap,nocap}
% \opt{cap} 和 \opt{nocap} 是过时选项。
% \begin{macrocode}
    cap    .code:n = { \ctex_set_deprecated_option:n { scheme = chinese } } ,
    nocap  .code:n = { \ctex_set_deprecated_option:n { scheme = plain } } ,
    cap    .value_forbidden:n = true ,
    nocap  .value_forbidden:n = true ,
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2015/04/20}{\opt{hyperref} 成为过时选项，原选项功能总是打开。}
% \changes{v2.0}{2015/04/20}{\opt{fancyhdr} 成为过时选项，原选项功能总是打开。}
% \changes{v2.0}{2015/04/20}{\opt{fntef} 成为过时选项，原选项功能总是打开。}
%
% 以下三项都是过时的兼容选项，它们会载入有关宏包。
%
% \begin{macro}{fntef}
% \changes{v2.5}{2019/11/10}{仅在该选项启用时会载入 \pkg{CJKfntef} 或
% \pkg{xeCJKfntef} 宏包。}
%    \begin{macrocode}
    fntef .code:n =
      {
        \sys_if_engine_xetex:TF
          {
            \ctex_deprecated_option:n { `xeCJKfntef'~package~is~loaded. }
            \ctex_at_end:n { \RequirePackage { xeCJKfntef } }
          }
          {
            \sys_if_engine_pdftex:TF
              {
                \ctex_deprecated_option:n { `CJKfntef'~package~is~loaded. }
                \ctex_at_end:n { \RequirePackage { CJKfntef } }
              }
              {
                \ctex_deprecated_option:n
                  { Furthermore,~option~`fntef'~is~invalid~in~current~mode. }
              }
          }
      } ,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{fancyhdr}
%    \begin{macrocode}
    fancyhdr .code:n =
      {
        \ctex_deprecated_option:n { `fancyhdr'~package~is~loaded. }
        \ctex_at_end:n { \RequirePackage { fancyhdr } }
      } ,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{hyperref}
% \changes{v2.1}{2015/06/03}{补充定义 \tn{hypersetup}。}
%    \begin{macrocode}
    hyperref .code:n =
      {
        \ctex_deprecated_option:n { `hyperref'~package~will~be~loaded. }
        \ctex_at_end:n
          {
            \cs_if_exist:NF \hypersetup
              { \cs_new_eq:NN \hypersetup \ctex_hypersetup:n }
          }
        \ctex_at_end_preamble:n { \RequirePackage { hyperref } }
      } ,
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</class|ctex>
%<*class|ctex|ctexsize>
%    \end{macrocode}
%
% \changes{v2.0}{2015/05/06}{兼容 \pkg{extsizes} 宏包、\cls{beamer}、\pkg{memoir}
% 等提供的更多字号选项。}
% \changes{v2.0.1}{2015/05/15}{修复 \opt{10pt}、\opt{11pt} 等选项无效的问题。}
% \begin{macro}{10pt,11pt,12pt}
% 使 \pkg{ctex} 和 \pkg{ctexsize} 可以接受文档类的全局选项，不修改默认字体大小。
% 在文档类下还将参数传给标准文档类。
%    \begin{macrocode}
\tl_clear_new:N \l_@@_tmp_tl
\clist_map_inline:nn
  {
    10pt , 11pt , 12pt ,
     8pt ,  9pt , 14pt , 17pt , 20pt , 25pt , 30pt , 36pt , 48pt , 60pt
  }
  {
    \tl_put_right:Nn \l_@@_tmp_tl
      {
        #1 .code:n =
%<*!class>
          { \int_gset:Nn \g_@@_font_size_int { 2 } } ,
%</!class>
%<*class>
          {
            \int_gset:Nn \g_@@_font_size_int { 2 }
            \clist_gput_right:Nn \g_@@_std_options_clist {#1}
          } ,
%</class>
        #1 .value_forbidden:n = true ,
      }
  }
\exp_args:No \ctex_define_option:n { \l_@@_tmp_tl }
\tl_clear:N \l_@@_tmp_tl
%    \end{macrocode}
% \end{macro}
%
% 将未知选项传给标准文档类。
%    \begin{macrocode}
%<*class>
\ctex_define_option:n
  {
    unknown .code:n =
      { \clist_gput_right:No \g_@@_std_options_clist { \CurrentOption } }
  }
%</class>
%    \end{macrocode}
%
% 载入选项配置文件。
%    \begin{macrocode}
%<!ctexsize>\ctex_file_input:n { ctexopts.cfg }
%</class|ctex|ctexsize>
%    \end{macrocode}
%
% 处理宏包选项。
%    \begin{macrocode}
%<*class|style>
\cs_if_exist:NTF \ProcessKeyOptions
  { \ProcessKeyOptions [ ctex / option ] }
  {
    \RequirePackage { l3keys2e }
    \ProcessKeysOptions { ctex / option }
  }
%</class|style>
%    \end{macrocode}
%
% \pdfLaTeX{} 下，如果没有显式指定编码为 |UTF8|，则给出警告信息。
%    \begin{macrocode}
%<*class|ctex>
\msg_new:nnn { ctex } { pdftex-utf8 }
  { UTF8~will~be~used~as~the~default~encoding. }
\tl_if_empty:NT \g_@@_encoding_tl
  {
    \sys_if_engine_pdftex:T
      { \msg_warning:nn { ctex } { pdftex-utf8 } }
    \tl_gset:Nn \g_@@_encoding_tl { UTF8 }
  }
%</class|ctex>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*class>
%    \end{macrocode}
%
% 五号字使用标准文档类的 |10pt| 字体大小设置，小四号字则使用 |12pt|。
%    \begin{macrocode}
\int_case:nn { \g_@@_font_size_int }
  {
    { 0 } { \clist_gput_right:Nn \g_@@_std_options_clist { 10pt } }
    { 1 } { \clist_gput_right:Nn \g_@@_std_options_clist { 12pt } }
  }
%    \end{macrocode}
%
% 载入标准文档类。
%    \begin{macrocode}
%<*article>
\ctex_load_std_class:n { article }
%</article>
%<*book>
\ctex_load_std_class:n { book }
%</book>
%<*report>
\ctex_load_std_class:n { report }
%</report>
%<*beamer>
\ctex_load_std_class:n { beamer }
%</beamer>
%    \end{macrocode}
%
%    \begin{macrocode}
%</class>
%    \end{macrocode}
%
% \changes{v2.1}{2015/06/16}{不再设置 \pkg{hyperref} 宏包的 \opt{colorlinks} 选项。}
%
% 现在处理各个引擎下的 PDF 中文书签问题。根据编译引擎与文件编码的不
% 同，\pkg{ctex} 向 \pkg{hyperref} 传递适当的参数，完成中文书签的正确设置。用
% 户仍需要自己载入 \pkg{hyperref} 宏包。
%
% \begin{macro}[int]{\ctex_hypersetup:n}
% 如果已经载入 \pkg{hyperref} 宏包，则直接使用其定义设置选项；否则
% \cs{ctex_hypersetup:n} 的效果与 \tn{PassOptionsToPackage} 一致，只传递宏包参
% 数。如果用户不载入 \pkg{hyperref} 宏包，相关参数即被丢弃。
%    \begin{macrocode}
%<*class|ctex>
\@ifpackageloaded { hyperref }
  {
    \cs_new_protected:Npn \ctex_hypersetup:n #1
      { \hypersetup {#1} }
  }
  {
    \cs_new_protected:Npn \ctex_hypersetup:n #1
      { \PassOptionsToPackage {#1} { hyperref } }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{载入引擎定义文件}
%
% 最后载入 \ref{subsubsec:hyperref}~中的各个编译引擎的定义文件。
%    \begin{macrocode}
\ctex_file_input:n { \c_@@_engine_file_str }
%</class|ctex>
%    \end{macrocode}
%
% \subsection{用户设置接口}
%
% \changes{v2.0}{2014/03/18}{新增统一设置接口 \tn{ctexset}。}
% \changes{v2.4.12}{2018/01/14}
%   {修正 \tn{ctexset} 在 \pkg{ctexheading} 包中无定义的错误（曾祥东）。 }
%
% \begin{macro}{\ctexset}
%    \begin{macrocode}
%<*class|ctex|ctexheading>
\NewDocumentCommand \ctexset { } { \ctex_set:n }
%</class|ctex|ctexheading>
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2015/03/21}{\tn{CTEXsetup}, \tn{CTEXoptions} 是过时命令。}
% \begin{macro}{\CTEXsetup,\CTEXoptions}
% 过时命令。
%    \begin{macrocode}
%<*class|ctex>
\NewDocumentCommand \CTEXsetup { +O { } > { \TrimSpaces } m }
  {
    \tl_if_blank:nTF {#1}
      { \ctex_deprecated_command:Nn \CTEXsetup { } }
      {
        \ctex_deprecated_command:Nn \CTEXsetup
          { \ctexset {~#2~=~{~#1~}~}~is~set. }
        \ctex_set:nn {#2} {#1}
      }
  }
\NewDocumentCommand \CTEXoptions { +O { } }
  {
    \tl_if_blank:nTF {#1}
      { \ctex_deprecated_command:Nn \CTEXoptions { } }
      {
        \ctex_deprecated_command:Nn \CTEXoptions
          { \ctexset {~#1~}~is~set. }
        \ctex_set:n {#1}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{字距与缩进}
%
% \begin{macro}{autoindent}
% \opt{autoindent} 也是可以用在正文中的选项，意义与宏包选项 |option/autoindent| 相同。
%    \begin{macrocode}
\ctex_define:n
  {
    autoindent .choice: ,
    autoindent .default:n = { true } ,
    autoindent / true    .code:n =
      {
        \tl_set:Nn \l_@@_autoindent_tl { 2 \ccwd }
        \ctex_select_size:
      } ,
    autoindent / false   .code:n =
      { \tl_clear:N \l_@@_autoindent_tl } ,
    autoindent / unknown .code:n =
      {
        \ctex_set_default_ccwd:Nn \l_@@_autoindent_tl {#1}
        \ctex_select_size:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CTEXsetfont}
% 无论字体大小是否变化都更新相关信息。
%    \begin{macrocode}
\NewDocumentCommand \CTEXsetfont { } { \ctex_select_size: }
\cs_new_protected:Npn \ctex_select_size:
  { \cs_if_free:NTF \size@update { \ctex_update_size: } { \selectfont } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_update_size:}
% 在字号变化时更新 \tn{ccwd}、\tn{parindent} 和汉字间距。字距为零则恢复正常设置。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_update_size:
  {
    \tl_if_eq:NNTF \l_@@_ziju_tl \c_@@_zero_tl
      {
        \ctex_update_stretch:
        \ctex_update_parindent:
      }
      { \ctex_update_ziju: }
  }
\tl_const:Ne \c_@@_zero_tl { \fp_use:N \c_zero_fp }
\tl_new:N \l_@@_ziju_tl
\tl_set_eq:NN \l_@@_ziju_tl \c_@@_zero_tl
%    \end{macrocode}
% 在 \tn{selectfont} 中，若 \tn{size@update} 为 \tn{relax}，说明字体大小没有变化，
% 我们也就不用更新相关参数。
%    \begin{macrocode}
\ctex_add_to_selectfont:n
  { \cs_if_free:NF \size@update { \ctex_update_size: } }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/26}{新增 \opt{linestretch} 选项。}
%
% \begin{macro}{linestretch}
% 若行宽不是汉字宽度的整数倍，自然要求伸展它们之间的差。这里设置的是在此基础上的
% 额外伸展量。初始化为一个汉字的宽度。若设置为 \tn{maxdimen}，则禁用此功能。
% 参数的默认单位是汉字的宽度 \tn{ccwd}。
%    \begin{macrocode}
\ctex_define:n
  {
    linestretch .code:n =
      {
        \ctex_set_default_ccwd:Nn \l_@@_line_stretch_tl {#1}
        \ctex_select_size:
      } ,
    linestretch .value_required:n = true
  }
\tl_new:N \l_@@_line_stretch_tl
\tl_set:Nn \l_@@_line_stretch_tl { \ccwd }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_update_stretch:}
% 首先计算一行上汉字的字数，\tn{CJKglue} 相当于将 \tn{linewidth} 与汉字总宽度之差
% 均匀地填充到汉字之间。\hologo{eTeX} 的除法是四舍五入，而我们这里应该用截断。由于
% 没有可展性的要求，直接用原语 \cs{tex_divide:D} 要比 \cs{int_div_truncate:nn}
% 快一些。下面的算法还兼顾到了 \tn{linewidth} 不为汉字字宽的整数倍的情况。
% 若用户禁用 \opt{linestretch} 并且修改过 \tn{CJKglue}，则只更新
% \tn{ccwd}，否则设置伸展量为 $0.08$ 倍 \tn{baselineskip}。注意 \pkg{everysel} 的
% 钩子位于 \tn{size@update} 之前，\tn{baselineskip} 还未更新，不能直接使用它。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_update_stretch:
  {
    \ctex_update_em_unit:
    \dim_set:Nn \l_@@_tmp_dim { \l_@@_line_stretch_tl }
    \dim_compare:nNnTF \l_@@_tmp_dim = \c_max_dim
      { \@@_update_stretch_auxi: }
      { \@@_update_stretch_auxii: }
  }
\cs_new_protected:Npn \@@_update_stretch_auxi:
  {
    \ctex_if_ccglue_touched:TF
      { \ctex_update_ccwd: }
      {
        \dim_set:Nn \l_@@_tmp_dim
          { \baselinestretch \tex_glueexpr:D \f@baselineskip \scan_stop: }
        \skip_set:Nn \l_@@_ccglue_skip
          { \c_zero_dim plus .08 \l_@@_tmp_dim }
        \ctex_update_ccglue:
      }
  }
\cs_new_protected:Npn \@@_update_stretch_auxii:
  { \@@_update_stretch_auxiii: }
\cs_new_protected:Npn \@@_update_stretch_auxiii:
  {
    \int_set:Nn \l_@@_tmp_int
      { \tex_dimexpr:D \linewidth - \ccwd - \l_@@_tmp_dim \scan_stop: }
    \tex_divide:D \l_@@_tmp_int \ccwd
    \int_compare:nNnTF \l_@@_tmp_int > \c_zero_int
      {
        \skip_set:Nn \l_@@_ccglue_skip
          {
            \c_zero_dim plus \dim_eval:n
              {
                ( \linewidth - \ccwd - \l_@@_tmp_int \ccwd ) /
                \l_@@_tmp_int
              }
          }
      }
      { \skip_zero:N \l_@@_ccglue_skip }
    \ctex_update_ccglue:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_update_parindent:}
% 更新段落首行缩进。此函数在字号变化时调用。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_update_parindent:
  {
    \tl_if_empty:NF \l_@@_autoindent_tl
      {
        \dim_compare:nNnF \parindent = \c_zero_dim
          { \dim_set:Nn \parindent { \l_@@_autoindent_tl } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ziju}
% 若参数为 $0$，则恢复正常间距。
%    \begin{macrocode}
\NewDocumentCommand \ziju { m }
  { \exp_args:Ne \ctex_ziju:n {#1} \tex_ignorespaces:D }
\cs_new_protected:Npn \ctex_ziju:n #1
  {
    \tl_set:Ne \l_@@_ziju_tl { \fp_eval:n {#1} }
    \ctex_select_size:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_update_ziju:}
% 更新字距。若字距不大于 $-1$，即 \tn{ccwd} 为非正值，则不计算伸缩值。
% 否则，首先假定汉字的宽度为正常宽度加上字距，看一行上能正常放下多少个汉字。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_update_ziju:
  {
    \ctex_update_em_unit:
    \dim_set:Nn \l_@@_ziju_dim { \l_@@_ziju_tl \ccwd }
    \dim_add:Nn \ccwd { \l_@@_ziju_dim }
    \dim_compare:nNnTF \ccwd > \c_zero_dim
%    \end{macrocode}
% 伸展量保证行内的剩余空白能够被均匀地填充到汉字之间，收缩的最大限度是让当前行
% 还能够再挤下一个汉字并且不会出现负间距。由 \TeX{} 决定伸展还是收缩。
%    \begin{macrocode}
      {
        \dim_set:Nn \l_@@_tmp_dim
          { \linewidth - \ccwd + \l_@@_ziju_dim }
        \int_set:Nn \l_@@_tmp_int { \l_@@_tmp_dim }
        \tex_divide:D \l_@@_tmp_int \ccwd
        \dim_sub:Nn \l_@@_tmp_dim { \l_@@_tmp_int \ccwd }
%    \end{macrocode}
% 由于 \tn{parindent} 是一个固定值，并不参与伸缩，容易导致第一行出现坏盒子。
% 我们在这里将字数减去 $2$，以此放大伸缩值。
%    \begin{macrocode}
        \dim_compare:nNnF \parindent = \c_zero_dim
          {
            \int_compare:nNnF \l_@@_tmp_int < 3
              { \int_sub:Nn \l_@@_tmp_int { 2 } }
          }
        \skip_set:Nn \l_@@_ccglue_skip
          {
            \l_@@_ziju_dim
            plus  \dim_eval:n { \l_@@_tmp_dim / \l_@@_tmp_int }
            minus \dim_min:nn { \dim_abs:n { \l_@@_ziju_dim } }
              { ( \ccwd - \l_@@_tmp_dim ) / ( \l_@@_tmp_int + 1 ) }
          }
      }
      { \skip_set:Nn \l_@@_ccglue_skip { \l_@@_ziju_dim } }
    \ctex_update_ccglue:
%    \end{macrocode}
% 字距设置得比较大时，为了尽量保证段首缩进能够与下一行对齐，应该需要相应地加上
% 或者减去伸缩值。但是这里并不清楚 \TeX{} 是伸展还是收缩，之前以“当前行是否还
% 放得下一个汉字”为标准加上或减去伸缩值的做法也未必与实际结果一致，所以只好还
% 是设置为 |2\ccwd|。
%    \begin{macrocode}
    \ctex_update_parindent:
  }
\dim_new:N \l_@@_ziju_dim
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2015/03/21}{\tn{CTEXindent}, \tn{CTEXnoindent} 是过时命令。}
% \begin{macro}{\CTEXindent,\CTEXnoindent}
% 过时命令。
%    \begin{macrocode}
\NewDocumentCommand \CTEXindent { }
  {
    \ctex_deprecated_command:Nn \CTEXindent
      { \parindent is~set~to~2\ccwd. }
    \ctex_update_ccwd:
    \dim_set:Nn \parindent { 2 \ccwd }
  }
\NewDocumentCommand \CTEXnoindent { }
  {
    \ctex_deprecated_command:Nn \CTEXnoindent
      { \parindent is~set~to~0pt. }
    \dim_zero:N \parindent
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{中文数字与日期}
%
% 需要注意的是，\pkg{ltkeys} 设置的选项列表是
% |\@raw@opt@|\meta{\textbackslash @currname}|.|\meta{\textbackslash @currext}，
% 该列表不会将 \tn{PassOptionsToPackage} 传递的选项完全展开。
%    \begin{macrocode}
\exp_args:Ne \PassOptionsToPackage
  { encoding = \g_@@_encoding_tl }
  { zhnumber }
\RequirePackage { zhnumber }
%    \end{macrocode}
%
% \begin{macro}{\chinese}
% \changes{v2.4.1}{2016/05/01}{支持 \tn{pagenumbering}。}
%    \begin{macrocode}
\cs_new:Npn \chinese { \zhnum_counter:n }
\cs_new_eq:NN \@chinese \@zhnum
\cs_new_eq:NN \Chinese \chinese
\cs_new_eq:NN \CTEXcounter \use_none:n
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.2}{2015/06/29}{给 \pkg{enumitem} 宏包注册 \tn{chinese} 和
%   \tn{zhnum}。}
%
% 给 \pkg{enumitem} 宏包注册 \tn{chinese}、\tn{zhnum} 和 \tn{zhdig}。
%    \begin{macrocode}
\ctex_at_end_package:nn { enumitem }
  {
    \cs_if_free:NF \AddEnumerateCounter
      {
        \AddEnumerateCounter * { \zhnum }   { \@zhnum } { 1 }
        \AddEnumerateCounter * { \zhdig }   { \@zhdig } { 1 }
        \AddEnumerateCounter * { \chinese } { \@chinese } { 1 }
      }
  }
%    \end{macrocode}
%
% \begin{macro}{\CTEXnumber,\CTEXdigits}
%    \begin{macrocode}
\NewDocumentCommand \CTEXnumber { m m }
  { \protected@edef #1 { \zhnumber {#2} } }
\NewDocumentCommand \CTEXdigits { m m }
  { \protected@edef #1 { \zhdigits {#2} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{today}
%    \begin{macrocode}
\cs_set_eq:NN \CTEX@todayold \today
\ctex_define:n
  {
    today .choice: ,
    today / old     .code:n =
      { \cs_set_eq:NN \today \CTEX@todayold } ,
    today / small   .code:n =
      {
        \cs_set_eq:NN \today \zhtoday
        \zhnumsetup { time = Arabic }
      } ,
    today / big     .code:n =
      {
        \cs_set_eq:NN \today \zhtoday
        \zhnumsetup { time = Chinese }
      } ,
    today / unknown .code:n =
      { \msg_error:nne { ctex } { today-undef } {#1} }
  }
\msg_new:nnnn { ctex } { today-undef }
  { Today~format~`#1'~is~undefined. }
  { Available~today~formats~are~`old',~`small',~and~`big'. }
%    \end{macrocode}
% \end{macro}
%
% \subsection{其他中文标题定义}
%
% \changes{v2.0}{2014/03/08}{将标题汉化功能加入 \file{ctex.sty}。}
% \changes{v2.4.3}{2016/08/18}{确保 \tn{proofname} 非空。}
%
% \begin{macro}[int]{\proofname}
% \tn{proofname} 未在标准文档类中定义，需要确保它非空。
%    \begin{macrocode}
\tl_if_exist:NF \proofname
  {
    \tl_new:N \proofname
    \tl_set:Nn \proofname { Proof }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\ctex_define:n
  {
    contentsname   .tl_set:N = \contentsname ,
    listfigurename .tl_set:N = \listfigurename ,
    listtablename  .tl_set:N = \listtablename ,
    figurename     .tl_set:N = \figurename ,
    tablename      .tl_set:N = \tablename ,
    abstractname   .tl_set:N = \abstractname ,
    indexname      .tl_set:N = \indexname ,
    appendixname   .tl_set:N = \appendixname ,
    proofname      .tl_set:N = \proofname ,
%<article>    bibname        .tl_set:N = \refname
%<book|report>    bibname        .tl_set:N = \bibname
%<*beamer>
    algorithmname  .tl_set:N = \algorithmname ,
    bibname        .tl_set:N = \bibname ,
    refname        .tl_set:N = \refname ,
    continuation   .tl_set:N = \insertcontinuationtext
%</beamer>
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%<*ctex>
\msg_new:nnn { ctex } { ctexbibname }
  {
    Neither~`\token_to_str:N \bibname'~nor~`\token_to_str:N \refname'~can~be~found.\\
    The~key~`bibname'~will~set~`\token_to_str:N \ctexbibname'~to~the~given~value.
  }
\tl_if_exist:NTF \insertcontinuationtext
  {
    \ctex_define:n
      {
        algorithmname .tl_set:N = \algorithmname ,
        bibname       .tl_set:N = \bibname ,
        refname       .tl_set:N = \refname ,
        continuation  .tl_set:N = \insertcontinuationtext
      }
  }
  {
    \tl_if_exist:NTF \bibname
      { \ctex_define:n { bibname .tl_set:N = \bibname } }
      {
        \tl_if_exist:NTF \refname
          { \ctex_define:n { bibname .tl_set:N = \refname } }
          {
            \msg_warning:nn { ctex } { ctexbibname }
            \ctex_define:n { bibname .tl_set:N = \ctexbibname }
          }
      }
  }
%</ctex>
%    \end{macrocode}
%
%    \begin{macrocode}
%</class|ctex>
%    \end{macrocode}
%
% \subsection{中文化的标题结构}
%
% 本节内容在 \CTeX{} 文档类或打开 \opt{heading} 选项下生效。
%    \begin{macrocode}
%<*class|heading>
%    \end{macrocode}
%
% \subsubsection{定义标题格式选项}
%
% \begin{variable}{\c_@@_section_headings_seq}
% 保存 \tn{section} 级以下标题名字。
%    \begin{macrocode}
%<*article|book|report>
\seq_const_from_clist:Nn \c_@@_section_headings_seq
  { section , subsection , subsubsection , paragraph , subparagraph }
%</article|book|report>
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\c_@@_headings_seq}
% 保存各级标题名字。
%    \begin{macrocode}
%<article|book|report|beamer>\seq_const_from_clist:Nn \c_@@_headings_seq
%<*article|book|report>
  {
    part ,
%<book|report>    chapter ,
    section , subsection , subsubsection , paragraph , subparagraph
  }
%</article|book|report>
%<beamer>  { part , section , subsection }
%    \end{macrocode}
% \end{variable}
%
% \changes{v2.1}{2015/06/19}{\opt{nameformat} 可以接受章节名字为参数。}
% \changes{v2.3}{2016/01/05}{修复 \opt{nameformat} 作用域问题。}
%
% \begin{macro}{\@@_initial_heading:n}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_initial_heading:n #1
  {
    \tl_new:c { CTEX@pre#1 }
    \tl_new:c { CTEX@post#1 }
    \tl_const:ce { CTEXthe#1 }
      {
        \exp_not:c { CTEX@pre#1 }
        \exp_not:c { CTEX@the#1 }
        \exp_not:c { CTEX@post#1 }
      }
    \tl_const:ce { CTEX@#1name }
      {
        \group_begin:
          \exp_not:c { CTEX@#1@nameformat }
            {
              \exp_not:c { CTEX@pre#1 }
              \exp_not:N \tl_if_empty:NTF
              \exp_not:c { CTEX@#1@numberformat }
                { \exp_not:c { CTEX@the#1 } }
                {
                  \group_begin:
                    \exp_not:c { CTEX@#1@numberformat }
                    \exp_not:c { CTEX@the#1 }
                  \group_end:
                }
              \exp_not:c { CTEX@post#1 }
            }
        \group_end:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.1}{2015/05/22}{\opt{format+}, \opt{nameformat+} 等带加号的选项，
%   加号与前面的文字之间可以有可选的空格。}
% \changes{v2.1}{2015/06/19}{新的标题格式选项 \opt{aftertitle}。}
% \changes{v2.2}{2015/06/21}{新的标题格式选项 \opt{numbering}。}
% \changes{v2.2}{2015/06/27}{\opt{beforeskip} 和 \opt{afterskip} 选项的符号
%   不再有特殊意义。}
% \changes{v2.2}{2015/06/27}{新的标题格式选项 \opt{afterindent}。}
% \changes{v2.2}{2015/06/27}{新的标题格式选项 \opt{runin}。}
% \changes{v2.4.3}{2016/06/03}{新的标题格式选项 \opt{fixskip}。}
% \changes{v2.4.4}{2016/09/19}{新的标题格式选项 \opt{break}。}
% \changes{v2.4.5}{2016/10/22}{新的标题格式选项 \opt{hang}。}
% \changes{v2.4.5}{2016/10/25}{新的标题格式选项 \opt{tocline}。}
% \changes{v2.4.11}{2017/11/21}{因上游 \pkg{l3keys} 变化，重新定义
%   \opt{format\textvisiblespace+} 等带空格加号的选项。}
%
% \begin{macro}{\@@_def_heading_keys:n}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_def_heading_keys:n #1
  {
    \exp_args:NNe \tl_put_right:Nn \l_@@_tmp_tl
      {
        #1                  .meta:nn = { ctex / #1 } { ##1 } ,
        #1 / name            .code:n =
          { \ctex_assign_heading_name:nn {#1} { ##1 } } ,
        #1 / number        .tl_set:N = \exp_not:c { CTEX@the#1 } ,
        #1 / beforeskip    .tl_set:N = \exp_not:c { CTEX@#1@beforeskip } ,
        #1 / afterskip     .tl_set:N = \exp_not:c { CTEX@#1@afterskip} ,
        #1 / indent        .tl_set:N = \exp_not:c { CTEX@#1@indent } ,
        #1 / numbering   .bool_set:N = \exp_not:c { CTEX@#1@numbering } ,
        #1 / numbering    .initial:n = true ,
        #1 / beforeskip   .initial:n = \c_zero_skip ,
        #1 / afterskip    .initial:n = \c_zero_skip ,
        #1 / indent       .initial:n = \c_zero_dim ,
        #1 / beforeskip   .value_required:n = true ,
        #1 / afterskip    .value_required:n = true ,
        #1 / indent       .value_required:n = true ,
%<*article|book|report>
        #1 / afterindent .bool_set:N = \exp_not:c { CTEX@#1@afterindent } ,
        #1 / fixskip     .bool_set:N = \exp_not:c { CTEX@#1@fixskip } ,
        #1 / hang        .bool_set:N = \exp_not:c { CTEX@#1@hang } ,
        #1 / hang         .initial:n = true ,
        #1 / runin       .bool_set:N = \exp_not:c { CTEX@#1@runin } ,
        #1 / tocline      .cs_set:Np = \exp_not:c { CTEX@#1@tocline } ##1##2 ,
        \@@_plus_key_aux:nn {#1} { break } ,
%</article|book|report>
        \@@_plus_key_aux:nn {#1} { format } ,
        \@@_plus_key_aux:nn {#1} { nameformat } ,
        \@@_plus_key_aux:nn {#1} { numberformat } ,
        \@@_plus_key_aux:nn {#1} { titleformat } ,
        \@@_plus_key_aux:nn {#1} { aftername } ,
        \@@_plus_key_aux:nn {#1} { aftertitle } ,
      }
  }
\cs_new:Npn \@@_plus_key_aux:nn #1#2
  {
    #1 / #2   .tl_set:N = \exp_not:c { CTEX@#1@#2 } ,
    #1 / #2 +   .code:n =
      { \tl_put_right:Nn \exp_not:c { CTEX@#1@#2 } { ##1 } } ,
    #1 / #2 ~ + .code:n =
      { \tl_put_right:Nn \exp_not:c { CTEX@#1@#2 } { ##1 } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_assign_heading_name:nn}
% \begin{macro}{\@@_assign_heading_name:nnn}
% \opt{name} 的值是一个至多两个元素的逗号分隔列表。由于 \LaTeXiii{} 的
% \texttt{clist} 总是会自动忽略空元素，所以设置 |name={,章}| 后，第一个元素将会
% 是“章”，必须用空的分组保护空元素：|name={{},章}|，这在使用中有些许不便。我们
% 可以改用 \texttt{seq} 或者手写函数解析参数来加以改进。为实现的简单起见，这里用
% 了 \pkg{xparse} 的 \tn{SplitArgument}，它带有参数的长度检查。
%    \begin{macrocode}
\NewDocumentCommand \ctex_assign_heading_name:nn
  { m > { \SplitArgument { 1 } { , } } +m }
  { \@@_assign_heading_name:nnn {#1} #2 }
\cs_new_protected:Npn \@@_assign_heading_name:nnn #1#2#3
  {
    \tl_set:cn { CTEX@pre#1 } {#2}
    \tl_if_novalue:nTF {#3}
      { \tl_clear:c { CTEX@post#1 } }
      { \tl_set:cn { CTEX@post#1 } {#3} }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \changes{v2.0}{2014/03/21}{标题设置新增 \opt{pagestyle} 选项。}
% \changes{v2.4.1}{2016/05/10}{新的标题格式选项 \opt{part/fixbeforeskip} 和
%   \opt{chapter/fixbeforeskip}。}
% \changes{v2.4.3}{2016/06/03}{删除选项 \opt{part/fixbeforeskip} 和
%   \opt{chapter/fixbeforeskip}。}
% \changes{v2.4.5}{2016/10/01}{新的标题格式选项 \opt{chapter/lofskip} 和
%   \opt{chapter/lotskip}。}
%
% \begin{macro}{part/pagestyle,chapter/pagestyle,chapter/lofskip,chapter/lotskip}
% 只在 \cls{ctexbook} 和 \cls{ctexrep} 下有定义。
%    \begin{macrocode}
\group_begin:
%<*book|report>
\tl_set:Nn \l_@@_tmp_tl
  {
    part    / pagestyle .tl_set:N = \CTEX@part@pagestyle ,
    chapter / pagestyle .tl_set:N = \CTEX@chapter@pagestyle ,
    chapter / lofskip   .tl_set:N = \CTEX@chapter@lofskip ,
    chapter / lotskip   .tl_set:N = \CTEX@chapter@lotskip ,
    chapter / lofskip  .initial:n = \c_zero_skip ,
    chapter / lotskip  .initial:n = \c_zero_skip ,
    chapter / lofskip  .value_required:n = true ,
    chapter / lotskip  .value_required:n = true ,
  }
%</book|report>
%<*article|beamer>
\tl_clear:N \l_@@_tmp_tl
%</article|beamer>
%    \end{macrocode}
% \end{macro}
%
% 定义标题键值选项。
%    \begin{macrocode}
\seq_map_inline:Nn \c_@@_headings_seq
  {
    \@@_initial_heading:n {#1}
    \@@_def_heading_keys:n {#1}
  }
\exp_args:NNo \group_end: \ctex_define:n { \l_@@_tmp_tl }
%    \end{macrocode}
%
% \changes{v2.6.3}{2026/07/14}{提供按层级查询标题编号、完整标签和编号开关的接口，
%   使 Beamer 主题作者可以通过公开接口读取并响应 CTeX 本地化编号设置，
%   而无需访问私有变量
%   （\#275）。}
% \begin{macro}{\CTEXheadingnumber,\CTEXheadinglabel,\CTEXifheadingnumbering}
% 查询标题设置，但不应用任何标题格式。
% \tn{CTEXheadinglabel} 是 \tn{CTEXthe}\meta{层级} 的参数化等价形式。
%    \begin{macrocode}
\NewExpandableDocumentCommand \CTEXheadingnumber { m }
  { \use:c { CTEX@the#1 } }
\NewExpandableDocumentCommand \CTEXheadinglabel { m }
  { \use:c { CTEXthe#1 } }
\NewExpandableDocumentCommand \CTEXifheadingnumbering { m }
  { \bool_if:cTF { CTEX@#1@numbering } }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5}{2020/04/23}{重构标题选项 \opt{indent} 和 \opt{hang}。}
%
% \begin{macro}[int]{\CTEX@heading@format@initial}
% 标题格式的一些初始设置，包括恢复默认字体，并禁用自动调整首行缩进，禁止在标题中分页。
% 同时用 \tn{noindent} 抑制首行缩进并进入水平模式。
% 统一在各级标题的 \opt{format} 选项之前使用。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@heading@format@initial
  {
    \normalfont
    \tl_clear:N \l_@@_autoindent_tl
    \int_set:Nn \tex_interlinepenalty:D { 10 000 }
    \tex_noindent:D
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_indent_box:n}
% 设置 \tn{parindent}，并插入用于产生缩进的盒子，如果缩进为 |0|，就不插入。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_indent_box:n #1
  {
    \dim_set:Nn \tex_parindent:D {#1}
    \@@_insert_indent:
  }
\cs_new_protected:Npn \@@_insert_indent:
  {
    \dim_compare:nNnF \tex_parindent:D = \c_zero_dim
      { \tex_indent:D }
  }
\cs_new_eq:NN \CTEX@indentbox \ctex_indent_box:n
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{标准标题命令的修改}
%
%    \begin{macrocode}
%<*article|book|report>
%    \end{macrocode}
%
% \begin{macro}[int]{\CTEX@fixtopskip}
% 修正 \cls{book} 和 \cls{report} 类的 \tn{part} 和 \tn{chapter} 标题之前的多余空行。
%    \begin{macrocode}
%<*book|report>
\cs_new_protected:Npn \CTEX@fixtopskip
  {
    \CTEX@fixheadingskip
    \dim_compare:nNnF \tex_pagegoal:D < \c_max_dim
      { \skip_sub:Nn \l_@@_heading_skip { \tex_topskip:D } }
  }
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\CTEX@fixheadingskip}
% 抑制行间粘连，修正标题前后的多余间距。事实上，减掉 \tn{parskip}，有一定的风险。
% 如果接下来的内容不会进入水平模式（例如在 \opt{format} 选项中使用 \tn{hrule} 或者 \tn{hbox}），
% \TeX{} 就不会加上 \tn{parskip}。这时候就需要用户把 \tn{parskip} 加到 \opt{beforeskip}
% 或者 \opt{afterskip} 作为修正。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@fixheadingskip
  {
    \par
    \dim_set:Nn \tex_prevdepth:D { -1000pt }
    \skip_sub:Nn \l_@@_heading_skip { \tex_parskip:D }
  }
\skip_new:N \l_@@_heading_skip
\cs_new_protected:Npn \CTEX@setheadingskip
  { \skip_set:Nn \l_@@_heading_skip }
\cs_new_eq:NN \CTEX@headingskip \l_@@_heading_skip
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.10}{2022/06/23}{展开传递 \opt{pagestyle} 的值。}
%
% \begin{macro}[int]{\CTEX@setthispagestyle}
% 将 \verb"\CTEX@(part|chapter)@pagestyle" 展开后再传给 \tn{thispagestyle}。
%    \begin{macrocode}
%<*book|report>
\cs_new_protected:Npn \CTEX@setthispagestyle #1
  { \exp_args:Ne \thispagestyle { \use:c { CTEX@#1@pagestyle } } }
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.4.4}{2016/09/18}{提供 \tn{partmark}。}
% \begin{macro}[int]{\partmark}
% 提供 \tn{partmark}。
%    \begin{macrocode}
\ProvideDocumentCommand \partmark { m }
  { \markboth { } { } }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.4.4}{2016/09/19}{提供 \tn{CTEXifname}。}
% \changes{v2.4.6}{2016/10/31}{\tn{CTEXifname} 初始为假。}
% \begin{macro}{\CTEXifname}
% \begin{macro}[int]{\CTEX@ifnametrue,\CTEX@ifnamefalse}
% 用于判断当前标题是否有编号。
%    \begin{macrocode}
\cs_new_eq:NN \CTEXifname \use_ii:nn
\cs_new_protected:Npn \CTEX@ifnametrue
  { \cs_set_eq:NN \CTEXifname \use_i:nn }
\cs_new_protected:Npn \CTEX@ifnamefalse
  { \cs_set_eq:NN \CTEXifname \use_ii:nn }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]{\CTEX@addloflotskip}
% 往插图和表格目录中加入额外间距。如果间距为零，则不加入。
%    \begin{macrocode}
%<*book|report>
\cs_new_protected:Npn \CTEX@addloflotskip #1
  {
    \skip_set:Nn \l_@@_heading_skip { \use:c { CTEX@#1@lofskip } }
    \skip_if_eq:nnF { \l_@@_heading_skip } { \c_zero_skip }
      {
        \addtocontents { lof }
          { \protect \addvspace { \skip_use:N \l_@@_heading_skip } }
      }
    \skip_set:Nn \l_@@_heading_skip { \use:c { CTEX@#1@lotskip } }
    \skip_if_eq:nnF { \l_@@_heading_skip } { \c_zero_skip }
      {
        \addtocontents { lot }
          { \protect \addvspace { \skip_use:N \l_@@_heading_skip } }
      }
  }
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\CTEX@addtocline}
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@addtocline #1#2
  { \addcontentsline { toc } {#1} { \use:c { CTEX@#1@tocline } {#1} {#2} } }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.2}{2015/06/27}{\opt{beforeskip}、\opt{afterskip} 和 \opt{indent}
%   选项支持表达式。}
% \changes{v2.4.15}{2019/03/31}{修正 \opt{part/indent} 和 \opt{chapter/indent} 的实现方法。}
% \changes{v2.4.15}{2019/03/31}{定义 \opt{part/hang} 和 \opt{chapter/hang}。}
% \changes{v2.4.16}{2019/05/11}{修正 \opt{part/indent} 和 \opt{chapter/indent}
%   的实现方法，在其标题内部禁用 \opt{autoindent}。}
%
% \changes{v2.5}{2020/04/22}{标题选项 \opt{format} 也可以接受参数。}
%
% \paragraph{part 的标题}
%
% \changes{v2.2}{2015/06/27}{非 \cls{ctexart} 类的 \opt{part/beforeskip} 和
%   \opt{part/afterskip} 选项有意义。}
%
% \begin{macro}[int]{\part}
%    \begin{macrocode}
%<*article>
\renewcommand\part{%
  \if@noskipsec \leavevmode \fi
  \par
  \CTEX@part@break
% \addvspace{4ex}%
  \CTEX@setheadingskip \CTEX@part@beforeskip
  \ifodd \CTEX@part@fixskip \CTEX@fixheadingskip \fi
  \addvspace \CTEX@headingskip
  \ifodd \CTEX@part@afterindent
   \@afterindenttrue
  \else
   \@afterindentfalse
  \fi
  \secdef\@part\@spart}
%</article>
%<*book|report>
\renewcommand\part{%
% \if@openright
%   \cleardoublepage
% \else
%   \clearpage
% \fi
  \CTEX@part@break
% \thispagestyle{plain}%
  \CTEX@setthispagestyle{part}%
  \if@twocolumn
    \onecolumn
    \@tempswatrue
  \else
    \@tempswafalse
  \fi
% \null\vfil
  \CTEX@setheadingskip \CTEX@part@beforeskip
  \ifodd \CTEX@part@fixskip \CTEX@fixtopskip \fi
  \vspace*{\CTEX@headingskip}%
  \secdef\@part\@spart}
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@part}
%    \begin{macrocode}
%<*article>
\def\@part[#1]#2{%
  \ifnum \c@secnumdepth >\m@ne
    \ifodd \CTEX@part@numbering
      \CTEX@ifnametrue
      \refstepcounter{part}%
%     \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}%
    \else
      \CTEX@ifnamefalse
      \CTEX@makeanchor{part*}%
%     \addcontentsline{toc}{part}{#1}%
    \fi
  \else
    \CTEX@ifnamefalse
    \CTEX@makeanchor{part*}%
%   \addcontentsline{toc}{part}{#1}%
  \fi
  \CTEX@gettitle{#1}%
  \CTEX@addtocline{part}{#1}%
  \partmark{#1}%
  \begingroup
%   \parindent \z@ \raggedright \interlinepenalty \@M \normalfont
    \CTEX@heading@format@initial
    \CTEX@part@format{%
%   \ifnum \c@secnumdepth >\m@ne
%     \Large\bfseries\partname\nobreakspace\thepart\par\nobreak
%   \fi
      \CTEX@headinghang{part}%
        {\CTEXifname{\CTEX@partname\CTEX@part@aftername}{}}%
%   \huge\bfseries #2%
        \CTEX@part@titleformat{#2}%
%   \markboth{}{}\par
        \CTEX@part@aftertitle}\par
  \endgroup
  \nobreak
% \vskip 3ex
  \CTEX@setheadingskip \CTEX@part@afterskip
  \ifodd \CTEX@part@fixskip \CTEX@fixheadingskip \fi
  \vskip \CTEX@headingskip
  \@afterheading}
%</article>
%<*book|report>
\def\@part[#1]#2{%
  \ifnum \c@secnumdepth >-2\relax
    \ifodd \CTEX@part@numbering
      \CTEX@ifnametrue
      \refstepcounter{part}%
%     \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}%
    \else
      \CTEX@ifnamefalse
      \CTEX@makeanchor{part*}%
%     \addcontentsline{toc}{part}{#1}%
    \fi
  \else
    \CTEX@ifnamefalse
    \CTEX@makeanchor{part*}%
%   \addcontentsline{toc}{part}{#1}%
  \fi
  \CTEX@gettitle{#1}%
  \CTEX@addtocline{part}{#1}%
%  \markboth{}{}%
  \partmark{#1}%
  \begingroup
%   \centering \interlinepenalty \@M \normalfont
    \CTEX@heading@format@initial
    \CTEX@part@format{%
%   \ifnum \c@secnumdepth >-2\relax
%     \huge\bfseries\partname\nobreakspace\thepart\par\vskip 20\p@
%   \fi
      \CTEX@headinghang{part}%
        {\CTEXifname{\CTEX@partname\CTEX@part@aftername}{}}%
%   \Huge\bfseries #2\par
      \CTEX@part@titleformat{#2}%
      \CTEX@part@aftertitle}\par
  \endgroup
  \@endpart}
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@spart}
%    \begin{macrocode}
%<*article>
\def\@spart#1{%
  \CTEX@ifnamefalse
  \CTEX@makeanchor@spart{part*}%
  \CTEX@gettitle{#1}%
  \begingroup
%   \parindent \z@ \raggedright \interlinepenalty \@M \normalfont
    \CTEX@heading@format@initial
    \CTEX@part@format{%
      \CTEX@headinghang{part}{}%
%   \huge \bfseries #1\par
      \CTEX@part@titleformat{#1}%
      \CTEX@part@aftertitle}\par
  \endgroup
  \nobreak
% \vskip 3ex
  \CTEX@setheadingskip \CTEX@part@afterskip
  \ifodd \CTEX@part@fixskip \CTEX@fixheadingskip \fi
  \vskip \CTEX@headingskip
  \@afterheading}
%</article>
%<*book|report>
\def\@spart#1{%
  \CTEX@ifnamefalse
  \CTEX@makeanchor@spart{part*}%
  \CTEX@gettitle{#1}%
  \begingroup
%   \centering \interlinepenalty \@M \normalfont
    \CTEX@heading@format@initial
    \CTEX@part@format{%
      \CTEX@headinghang{part}{}%
%    \Huge \bfseries #1\par%
      \CTEX@part@titleformat{#1}%
      \CTEX@part@aftertitle}\par
  \endgroup
  \@endpart}
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@endpart}
%    \begin{macrocode}
%<*book|report>
\def\@endpart{%
% \vfil
  \CTEX@setheadingskip \CTEX@part@afterskip
  \ifodd \CTEX@part@fixskip \CTEX@fixheadingskip \fi
  \vskip \CTEX@headingskip
  \newpage
  \if@twoside
    \if@openright
      \null
      \thispagestyle{empty}%
      \newpage
    \fi
  \fi
  \if@tempswa
    \twocolumn
  \fi}
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \paragraph{chapter 的标题}
%
%    \begin{macrocode}
%<*book|report>
%    \end{macrocode}
%
% \begin{macro}[int]{\chapter}
%    \begin{macrocode}
\renewcommand\chapter{%
% \if@openright\cleardoublepage\else\clearpage\fi
% \thispagestyle{plain}%
  \CTEX@chapter@break
  \CTEX@setthispagestyle{chapter}%
  \global\@topnum\z@
% \@afterindentfalse
  \ifodd \CTEX@chapter@afterindent
    \@afterindenttrue
  \else
    \@afterindentfalse
  \fi
  \secdef\@chapter\@schapter}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@chapter}
%    \begin{macrocode}
\def\@chapter[#1]#2{%
  \ifnum \c@secnumdepth >\m@ne
%<*book>
    \if@mainmatter
%</book>
      \ifodd \CTEX@chapter@numbering
        \CTEX@ifnametrue
        \refstepcounter{chapter}%
%       \typeout{\@chapapp\space\thechapter.}%
        \typeout{\CTEXthechapter}%
%       \addcontentsline{toc}{chapter}
%         {\protect\numberline{\thechapter}#1}%
      \else
        \CTEX@ifnamefalse
        \CTEX@makeanchor{\Hy@chapapp*}%
%       \addcontentsline{toc}{chapter}{#1}%
      \fi
%<*book>
    \else
      \CTEX@ifnamefalse
      \CTEX@makeanchor@chapter{\Hy@chapapp*}%
%     \addcontentsline{toc}{chapter}{#1}%
    \fi
%</book>
  \else
    \CTEX@ifnamefalse
    \CTEX@makeanchor@chapter{\Hy@chapapp*}%
%   \addcontentsline{toc}{chapter}{#1}%
  \fi
  \CTEX@gettitle{#1}%
  \CTEX@addtocline{chapter}{#1}%
  \chaptermark{#1}%
% \addtocontents{lof}{\protect\addvspace{10\p@}}%
% \addtocontents{lot}{\protect\addvspace{10\p@}}%
  \CTEX@addloflotskip{chapter}%
  \if@twocolumn
    \@topnewpage[\@makechapterhead{#2}]%
  \else
    \@makechapterhead{#2}%
  \@afterheading
  \fi}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@schapter}
%    \begin{macrocode}
\def\@schapter#1{%
  \CTEX@ifnamefalse
  \CTEX@makeanchor@schapter{\Hy@chapapp*}%
  \CTEX@gettitle{#1}%
  \if@twocolumn
    \@topnewpage[\@makeschapterhead{#1}]%
  \else
    \@makeschapterhead{#1}%
    \@afterheading
  \fi}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@makechapterhead}
%    \begin{macrocode}
\def\@makechapterhead#1{%
% \vspace*{50\p@}%
  \CTEX@setheadingskip \CTEX@chapter@beforeskip
  \ifodd \CTEX@chapter@fixskip \CTEX@fixtopskip \fi
  \vspace*{\CTEX@headingskip}%
  \begingroup
%   \parindent \z@ \raggedright \normalfont
    \CTEX@heading@format@initial
    \CTEX@chapter@format{%
%   \ifnum \c@secnumdepth >\m@ne
%     \if@mainmatter
%       \huge\bfseries\@chapapp\space\thechapter\par\nobreak\vskip 20\p@
%     \fi
%   \fi
      \CTEX@headinghang{chapter}%
        {\CTEXifname{\CTEX@chaptername\CTEX@chapter@aftername}{}}%
%   \Huge \bfseries #1\par\nobreak
      \CTEX@chapter@titleformat{#1}%
      \CTEX@chapter@aftertitle}\par
  \endgroup
  \nobreak
%  \vskip 40\p@
  \CTEX@setheadingskip \CTEX@chapter@afterskip
  \ifodd \CTEX@chapter@fixskip \CTEX@fixheadingskip \fi
  \vskip \CTEX@headingskip}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@makeschapterhead}
%    \begin{macrocode}
\def\@makeschapterhead#1{%
% \vspace*{50\p@}%
  \CTEX@setheadingskip \CTEX@chapter@beforeskip
  \ifodd \CTEX@chapter@fixskip \CTEX@fixtopskip \fi
  \vspace*{\CTEX@headingskip}%
  \begingroup
% \parindent \z@ \raggedright \normalfont \interlinepenalty\@M
    \CTEX@heading@format@initial
    \CTEX@chapter@format{%
      \CTEX@headinghang{chapter}{}%
%     \Huge \bfseries  #1\par\nobreak
      \CTEX@chapter@titleformat{#1}%
      \CTEX@chapter@aftertitle}\par
  \endgroup
  \nobreak
% \vskip 40\p@
  \CTEX@setheadingskip \CTEX@chapter@afterskip
  \ifodd \CTEX@chapter@fixskip \CTEX@fixheadingskip \fi
  \vskip \CTEX@headingskip}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</book|report>
%    \end{macrocode}
%
% \paragraph{section 类的标题}
%
% \begin{macro}[int]{\@startsection}
% \LaTeX 的标准参数是：
% \begin{quote}\small
%   \Arg{name}\Arg{level}\Arg{indent}\Arg{beforeskip}\Arg{afterskip}^^A
%   \Arg{style}|*|\oarg{altheading}\Arg{heading}
% \end{quote}
%    \begin{macrocode}
\def\@startsection#1#2#3#4#5#6{%
  \if@noskipsec \leavevmode \fi
  \par
% \@tempskipa #4\relax
% \@afterindenttrue
% \ifdim \@tempskipa <\z@
%   \@tempskipa -\@tempskipa \@afterindentfalse
% \fi
  \CTEX@update@sectionformat@n{#1}%
  \ifodd \CTEX@afterindent
    \@afterindenttrue
  \else
    \@afterindentfalse
  \fi
  \if@nobreak
    \everypar{}%
  \else
%   \addpenalty\@secpenalty\addvspace\@tempskipa
    \csname CTEX@#1@break\endcsname
    \CTEX@setheadingskip{#4}%
    \ifodd \CTEX@fixskip \CTEX@fixheadingskip \fi
    \addvspace \CTEX@headingskip
  \fi
  \@ifstar
    {\CTEX@makeanchor@ssect{#1*}\@ssect{#3}{#4}{#5}{#6}}%
    {\@dblarg{\@sect{#1}{#2}{#3}{#4}{#5}{#6}}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@seccntformat}
%    \begin{macrocode}
\def\@seccntformat#1{%
% \csname the#1\endcsname\quad}%
  \csname CTEX@#1name\endcsname
  \csname CTEX@#1@aftername\endcsname}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@sect}
%    \begin{macrocode}
\def\@sect#1#2#3#4#5#6[#7]#8{%
  \ifnum #2>\c@secnumdepth
    \CTEX@ifnamefalse
    \CTEX@makeanchor@sect{#1*}%
    \let\@svsec\@empty
  \else
    \ifodd \csname CTEX@#1@numbering\endcsname
      \CTEX@ifnametrue
      \refstepcounter{#1}%
      \protected@edef\@svsec{\@seccntformat{#1}\relax}%
    \else
      \CTEX@ifnamefalse
      \CTEX@makeanchor{#1*}%
      \let\@svsec\@empty
    \fi
  \fi
  \CTEX@gettitle{#7}%
% \@tempskipa #5\relax
% \ifdim \@tempskipa>\z@
  \unless \ifodd \CTEX@runin
    \begingroup
      \CTEX@heading@format@initial
      #6{%
%       \@hangfrom{\hskip #3\relax\@svsec}%
%       \interlinepenalty \@M #8\@@@@par
        \CTEX@sectionhang{#3}{\@svsec}%
        \csname CTEX@#1@titleformat\endcsname{#8}%
        \csname CTEX@#1@aftertitle\endcsname}\par
    \endgroup
    \csname #1mark\endcsname{#7}%
%   \addcontentsline{toc}{#1}{%
%     \ifnum #2>\c@secnumdepth \else
%       \protect\numberline{\csname the#1\endcsname}%
%     \fi
%     #7}%
    \CTEX@addtocline{#1}{#7}%
  \else
    \def\@svsechd{%
      #6{%
%       \hskip #3\relax \@svsec #8
        {\CTEX@indentbox{#3}}\@svsec
        \csname CTEX@#1@titleformat\endcsname{#8}%
        \csname CTEX@#1@aftertitle\endcsname}%
      \csname #1mark\endcsname{#7}%
%     \addcontentsline{toc}{#1}{%
%       \ifnum #2>\c@secnumdepth \else
%         \protect\numberline{\csname the#1\endcsname}%
%       \fi
%       #7}%
      \CTEX@addtocline{#1}{#7}}%
  \fi
  \@xsect{#5}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@ssect}
%    \begin{macrocode}
\def\@ssect#1#2#3#4#5{%
  \CTEX@ifnamefalse
  \CTEX@gettitle{#5}%
% \@tempskipa #3\relax
% \ifdim \@tempskipa>\z@
  \unless \ifodd \CTEX@runin
    \begingroup
      \CTEX@heading@format@initial
      #4{%
%       \@hangfrom{\hskip #1}%
%       \interlinepenalty \@M #5\@@par
        \CTEX@sectionhang{#1}{}%
          \CTEX@titleformat@n{#5}%
          \CTEX@aftertitle}\par
    \endgroup
  \else
%   \def\@svsechd{#4{\hskip #1\relax #5}}%
    \def\@svsechd{#4{{\CTEX@indentbox{#1}}%
      \CTEX@titleformat@n{#5}\CTEX@aftertitle}}%
  \fi
  \@xsect{#3}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@xsect}
%    \begin{macrocode}
\def\@xsect#1{%
% \@tempskipa #1\relax
% \ifdim \@tempskipa>\z@
  \unless \ifodd \CTEX@runin
    \par \nobreak
%   \vskip \@tempskipa
    \CTEX@setheadingskip{#1}%
    \ifodd \CTEX@fixskip \CTEX@fixheadingskip \fi
    \vskip \CTEX@headingskip
    \@afterheading
  \else
    \@nobreakfalse
    \global\@noskipsectrue
    \everypar{%
      \if@noskipsec
        \global\@noskipsecfalse
       {\setbox\z@\lastbox}%
        \clubpenalty\@M
        \begingroup \@svsechd \endgroup
        \unskip
%       \@tempskipa #1\relax
%       \hskip -\@tempskipa
        \CTEX@heading@glue{#1}%
      \else
        \clubpenalty \@clubpenalty
        \everypar{}%
      \fi}%
  \fi
  \ignorespaces}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\CTEX@headinghang,\CTEX@sectionhang}
% 分别用于用于实现 \tn{part}/\tn{chapter} 和 \tn{section} 类标题的
% \opt{indent} 和 \opt{hang} 选项。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@headinghang #1
  {
    \ctex_heading_hang:cnn
      { CTEX@#1@hang }
      { \use:c { CTEX@#1@indent } }
  }
\cs_new_protected:Npn \CTEX@sectionhang
  { \ctex_heading_hang:Nnn \CTEX@hang }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_heading_hang:Nnn,\ctex_hang_from:n}
% \opt{hang} 选项控制是否采用悬挂缩进，同时设置 \tn{parindent}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_heading_hang:Nnn #1#2#3
  {
    \dim_set:Nn \tex_parindent:D {#2}
    \bool_if:NTF #1
      { \ctex_hang_from:n }
      { \use:n }
      { \@@_insert_indent: #3 }
  }
\cs_new_protected:Npn \ctex_hang_from:n #1
  {
    \tex_noindent:D
    \hbox_set:Nn \l_@@_tmp_box {#1}
    \tex_hangindent:D = \box_wd:N \l_@@_tmp_box
    \box_use_drop:N \l_@@_tmp_box
  }
\cs_generate_variant:Nn \ctex_heading_hang:Nnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_heading_glue:n,\CTEX@heading@glue}
% 如果缩进 |#1| 长度为零，就不插入水平间距。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_heading_glue:n #1
  {
    \group_begin:
      \skip_set:Nn \l_@@_heading_skip {#1}
      \dim_compare:nNnF \l_@@_heading_skip = \c_zero_dim
        { \skip_horizontal:N \l_@@_heading_skip }
    \group_end:
  }
\cs_new_eq:NN \CTEX@heading@glue \ctex_heading_glue:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\CTEX@update@sectionformat@n}
% 在 \tn{@startsection} 中设置 \tn{CTEX@titleformat@n} 等为相应函数。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@update@sectionformat@n #1
  {
    \cs_set_eq:Nc \CTEX@titleformat@n { CTEX@#1@titleformat }
    \cs_set_eq:Nc \CTEX@aftertitle    { CTEX@#1@aftertitle }
    \cs_set_eq:Nc \CTEX@afterindent   { CTEX@#1@afterindent }
    \cs_set_eq:Nc \CTEX@fixskip       { CTEX@#1@fixskip }
    \cs_set_eq:Nc \CTEX@hang          { CTEX@#1@hang }
    \cs_set_eq:Nc \CTEX@runin         { CTEX@#1@runin }
  }
\cs_new_eq:NN \CTEX@titleformat@n \use:n
\cs_new_eq:NN \CTEX@aftertitle \prg_do_nothing:
\cs_new_eq:NN \CTEX@afterindent \c_true_bool
\cs_new_eq:NN \CTEX@fixskip \c_false_bool
\cs_new_eq:NN \CTEX@hang \c_true_bool
\cs_new_eq:NN \CTEX@runin \c_false_bool
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\CTEX@part@tocline, \CTEX@chapter@tocline}
%    \begin{macrocode}
\cs_new:Npn \CTEX@part@tocline #1#2
  {
    \CTEXifname
      { \CTEXthepart \hspace { 1em } }
      { }
    #2
  }
%<*book|report>
\cs_new:Npn \CTEX@chapter@tocline #1#2
  {
    \CTEXifname
      { \protect \numberline { \CTEXthechapter \hspace { .3em } } }
      { }
    #2
  }
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\CTEXnumberline}
%    \begin{macrocode}
\cs_new:Npn \CTEXnumberline #1
  {
    \CTEXifname
      { \protect \numberline { \use:c { CTEXthe #1 } } }
      { }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\int_zero:N \l_@@_tmp_int
\seq_map_inline:Nn \c_@@_section_headings_seq
  {
    \int_incr:N \l_@@_tmp_int
    \cs_gset_protected:cpx  {#1}
      {
        \exp_not:N \@startsection {#1}
          { \int_use:N \l_@@_tmp_int }
          { \exp_not:c { CTEX@#1@indent } }
          { \exp_not:c { CTEX@#1@beforeskip } }
          { \exp_not:c { CTEX@#1@afterskip } }
          { \exp_not:N \normalfont \exp_not:c { CTEX@#1@format } }
      }
    \cs_new:cpn { CTEX@#1@tocline } ##1##2
      { \CTEXnumberline { ##1 } ##2 }
  }
%    \end{macrocode}
%
% \paragraph{附录标题}
%
% \begin{macro}[int]{appendix/name,appendix/number,appendix/numbering}
%    \begin{macrocode}
\ctex_define:n
  {
    appendix                .meta:nn = { ctex / appendix } {#1} ,
    appendix / name          .code:n =
      { \ctex_assign_heading_name:nn { appendix } {#1} } ,
    appendix / number      .tl_set:N = \CTEX@appendix@number ,
    appendix / numbering .bool_set:N = \CTEX@appendix@numbering ,
    appendix / numbering  .initial:n = true
  }
\tl_new:N \CTEX@preappendix
\tl_new:N \CTEX@postappendix
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\appendix}
%    \begin{macrocode}
\cs_new_eq:NN \CTEX@save@appendix \appendix
\cs_gset_protected:Npn \appendix
  {
    \CTEX@save@appendix
%<*article>
    \gdef \CTEX@presection { \CTEX@preappendix }
    \gdef \CTEX@thesection { \CTEX@appendix@number }
    \gdef \CTEX@postsection { \CTEX@postappendix }
    \gdef \CTEX@section@numbering { \CTEX@appendix@numbering }
%</article>
%<*book|report>
    \gdef \CTEX@prechapter { \CTEX@preappendix }
    \gdef \CTEX@thechapter { \CTEX@appendix@number }
    \gdef \CTEX@postchapter { \CTEX@postappendix }
    \gdef \CTEX@chapter@numbering { \CTEX@appendix@numbering }
%</book|report>
  }
%    \end{macrocode}
% \end{macro}
%
% \paragraph{设置 \pkg{hyperref} 宏包的标题锚点}
%
% \changes{v2.4.4}{2016/09/12}{改进 \pkg{hyperref} 宏包的标题锚点设置。}
%
% \begin{macro}[int]{\CTEX@makeanchor}
% 设置超链接跳转锚点，在 \pkg{hyperref} 载入后才有意义。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@makeanchor #1
  { }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\c_@@_headings_cs_seq}
% 保存内部标题命令的 \CTeX{} 定义，用于随后比较。
%    \begin{macrocode}
\seq_const_from_clist:Nn \c_@@_headings_cs_seq
%<article>  { part , spart , sect , ssect }
%<book|report>  { part , spart , chapter , schapter , sect , ssect }
\seq_map_inline:Nn \c_@@_headings_cs_seq
  {
    \cs_new_eq:cc { CTEX@ #1 } { @ #1 }
    \cs_new_eq:cN { CTEX@makeanchor@ #1 } \CTEX@makeanchor
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[int]{\CTEX@hyperheadinghook}
% \pkg{hyperref} 会重定义内部标题命令，目的在于为没有编号的标题设置锚点（这一功能受他的
% \opt{implicit} 选项的控制）。我们在上面对标题命令的修改已经包含这一功能，如果这些标题命令在
% \pkg{hyperref} 载入之前没有被修改过，则恢复 \CTeX{} 的定义。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@hyperheadinghook
  {
    \group_begin:
      \legacy_if:nTF { Hy@implicit }
        {
          \cs_set_eq:NN \H@old@chapter \Hy@org@chapter
          \seq_map_inline:Nn \c_@@_headings_cs_seq
            {
              \cs_if_eq:ccT { H@old@ ##1 } { CTEX@ ##1 }
                {
                  \cs_gset_eq:cc { @ ##1 } { CTEX@ ##1 }
                  \cs_gset_eq:cN { CTEX@makeanchor@ ##1 } \CTEX@makeanchor
                }
            }
        }
        {
          \seq_map_inline:Nn \c_@@_headings_cs_seq
            { \cs_gset_eq:cN { CTEX@makeanchor@ ##1 } \CTEX@makeanchor }
        }
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\ctex_at_end_package:nn { hyperref }
  {
    \cs_gset_protected:Npn \CTEX@makeanchor #1
      {
        \Hy@MakeCurrentHrefAuto {#1}
        \Hy@raisedlink
          {
            \hyper@anchorstart { \@currentHref }
            \hyper@anchorend
          }
      }
    \CTEX@hyperheadinghook
  }
%    \end{macrocode}
%
% \paragraph{兼容 \pkg{nameref} 宏包}
%
% \changes{v2.4.16}{2019/05/29}{更好地兼容 \pkg{nameref} 宏包。}
%
% \begin{macro}[int]{\CTEX@gettitle}
% 在 \pkg{nameref} 载入后才有意义，与上述 \pkg{hyperref} 的处理类似。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@gettitle #1
  { }
\ctex_at_end_package:nn { nameref }
  {
    \cs_gset_protected:Npn \CTEX@gettitle { \NR@gettitle }
    \seq_map_inline:Nn \c_@@_headings_cs_seq
      {
        \cs_if_eq:ccT { NR@ #1 } { CTEX@ #1 }
          { \cs_gset_eq:cc { @ #1 } { CTEX@ #1 } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \paragraph{兼容 \pkg{titlesec} 宏包}
%
% 我们修改了 \tn{@startsection} 的定义，它的第四个（\meta{beforeskip}）和
% 第五个（\meta{afterskip}）参数的符号不再有特殊意义，改由相应的选项
% \opt{afterindent} 和 \opt{runin} 来控制。
%
% 引入 \pkg{titlesec} 宏包，并且未设置它的 \opt{loadonly} 选项时，\pkg{titlesec}
% 会展开 section 类标题获取它们的参数，进行初始设置。我们需要进行一些调整。
%
% \begin{macro}[int]{\ctex_titlesec_hook:}
% \tn{titleformat} 的设置保存在名为 |\ttlf@|\meta{section} 的宏中备用，它的内容是
% \begin{quote}\small
%   |\ttlh@|\meta{shape}\Arg{format}\Arg{label}\Arg{sep}\Arg{before}\Arg{after}
% \end{quote}
% 我们这里的 \meta{shape} 为 |hang| 或者 |runin|。\tn{titlespacing} 的设置保存在
% |\ttls@|\meta{section} 之中，它的内容是
% \begin{quote}\small
%   \Arg{left}\Arg{right}\Arg{before}\Arg{after}\Arg{afterindent}
% \end{quote}
% 其中 \meta{afterindent} 为 |1| 或 |0|，分别对应是否保留段首缩进。
% 我们需要根据 \CTeX{} 的 \opt{runin} 和 \opt{afterindent} 选项调整
% |\ttlh@|\meta{shape} 和 \meta{afterindent}。注意，由 \tn{ttl@extract} 得的
% \meta{before} 和 \meta{after} 的值总是非负的，而 \CTeX{} 的 \opt{beforeskip}
% 和 \opt{afterskip} 是可以取负值的，但我们不打算调整它们了。
% 如果使用了 \pkg{titlesec} 的 \opt{indentafter} 等选项，也不需要调整
% |\ttls@|\meta{section}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_titlesec_hook:
  {
    \@ifpackagewith { titlesec } { explicit }
      {
        \cs_set_eq:NN \@@_titlesec_format:Nn
                      \@@_titlesec_format_explicit:Nn
      }
      { }
    \clist_map_inline:nn
      { indentafter , noindentafter , indentfirst , nonindentfirst }
      {
        \@ifpackagewith { titlesec } { ##1 }
          {
            \clist_map_break:n
              { \cs_set_eq:NN \@@_titlesec_hook:n \@@_titlesec_format:n }
          }
          { }
      }
    \seq_map_function:NN \c_@@_section_headings_seq \@@_titlesec_hook:n
  }
\cs_new_protected:Npn \@@_titlesec_hook:n #1
  {
    \@@_titlesec_format:n {#1}
    \exp_args:Nc \@@_titlesec_spacing:Nn { ttls@#1 } {#1}
  }
\cs_new_protected:Npn \@@_titlesec_format:n #1
  {
    \cs_if_free:cF { ttlf@#1 }
      { \exp_args:Nc \@@_titlesec_format:Nn { ttlf@#1 } {#1} }
  }
\cs_new_protected:Npn \@@_titlesec_format:Nn #1#2
  {
    \tl_set:Ne #1
      {
        \bool_if:cTF { CTEX@#2@runin }
          { \exp_not:N \ttlh@runin }
          { \exp_not:N \ttlh@hang }
        \tl_tail:N #1
      }
  }
\cs_new_protected:Npn \@@_titlesec_format_explicit:Nn #1#2
  {
    \cs_set_nopar:Npx #1 ##1
      {
        \bool_if:cTF { CTEX@#2@runin }
          { \exp_not:N \ttlh@runin }
          { \exp_not:N \ttlh@hang }
        \exp_args:No \tl_tail:n { #1 { } }
      }
  }
\cs_new_protected:Npn \@@_titlesec_spacing:Nn #1#2
  { \tl_set:Ne #1 { \exp_after:wN \@@_titlesec_spacing:nnnnnn #1 {#2} } }
\cs_new:Npn \@@_titlesec_spacing:nnnnnn #1#2#3#4#5#6
  {
    \exp_not:n { {#1} {#2} {#3} {#4} }
    { \bool_if:cTF { CTEX@#6@afterindent } { \@ne } { \z@ } }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\@ifpackageloaded { titlesec }
  { }
  {
    \ctex_at_end_package:nn { titlesec }
      {
        \@ifpackagewith { titlesec } { loadonly }
          { }
          { \ctex_titlesec_hook: }
      }
  }
%    \end{macrocode}
%
% \changes{v2.4.4}{2016/09/13}{使用 \pkg{titlesec} 时，章节目录也使用 \CTeX{} 的编号。}
% 让编译时终端显示  \tn{CTEXthechapter}，目录使用 |\CTEXtheXXX| 编号。
%    \begin{macrocode}
\ctex_at_end_package:nn { titlesec }
  {
%<*book|report>
    \tl_set:Nn \ttl@chapterout { \typeout { \CTEXthechapter } }
%</book|report>
    \cs_if_free:NF \ttl@tocpart
      {
        \cs_set_protected:Npn \ttl@tocpart
          { \tl_set:Nn \ttl@a { \CTEXthepart \hspace { 1em } } }
      }
    \seq_map_inline:Nn \c_@@_headings_seq
      {
        \cs_if_exist:cF { ttl@toc #1 }
          {
            \cs_new_protected:cpx { ttl@toc #1 }
              {
                \tl_set:Nn \exp_not:N \ttl@a
                  {
                    \exp_not:N \protect
                    \exp_not:N \numberline { \exp_not:c { CTEXthe #1 } }
                  }
              }
          }
      }
  }
%    \end{macrocode}
%
% \changes{v2.5.8}{2021/12/04}{兼容 \pkg{titlesec} 包和 \tn{CTEXifname}。}
% 在 \pkg{titlesec} 包定义的标题中更新 \tn{CTEXifname}。
%    \begin{macrocode}
\ctex_at_end_package:nn { titlesec }
  {
    \ctex_patch_cmd:Nnn \ttl@labelling
      { \let \ifttl@toclabel \ifttl@label }
      {
        \let \ifttl@toclabel \ifttl@label
        \CTEX@updatettlifname
      }
    \cs_new_protected:Npn \CTEX@updatettlifname
      { \legacy_if:nTF { ttl@label } { \CTEX@ifnametrue } { \CTEX@ifnamefalse } }
  }
%    \end{macrocode}
%
% \paragraph{兼容 \pkg{titleps} 宏包}
%
% \changes{v2.3}{2015/12/25}{兼容 \pkg{titleps} 宏包。}
%
% 按照 \pkg{titleps} 宏包的实现机制，|\CTEXtheXXX| 等宏直到页眉排版时才会被展开，
% 这可能会造成问题\footnote{\url{https://github.com/CTeX-org/ctex-kit/issues/217}}。
%
% \begin{macro}[int]{\ctex_titleps_hook:}
% 我们修改 \pkg{titleps} 包的内部命令 \tn{ttl@settopmark} 和 \tn{ttl@setsubmark}，
% 将 |\CTEXtheXXX| 等加入更新队列中。
%    \begin{macrocode}
\group_begin:
\char_set_catcode_other:N \#
\cs_new_protected:Npn \ctex_titleps_hook:
  {
    \ctex_patch_cmd:Nnn \ttl@settopmark
      { \protect \@namedef { the#1 } { \@nameuse { the#1 } } }
      {
        \protect \@namedef { the#1 } { \@nameuse { the#1 } }
        \CTEX@titlepslabel@set {#1}
      }
    \ctex_patch_cmd:Nnn \ttl@setsubmark
      { \protect \@namedef { the#1 } { } }
      {
        \protect \@namedef { the#1 } { }
        \CTEX@titlepslabel@clear {#1}
      }
    \ctex_patch_cmd:Nnn \ttl@setsubmark
      { \protect \@namedef { the#2 } { \@nameuse { the#2 } } }
      {
        \protect \@namedef { the#2 } { \@nameuse { the#2 } }
        \CTEX@titlepslabel@set {#2}
      }
  }
\group_end:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\CTEX@titlepslabel@set,\CTEX@titlepslabel@clear}
% 这两个函数要在随后被 \tn{xdef} 展开来获得 |\CTEXtheXXX| 的内容，不应该用
% \tn{protected} 来定义。
%    \begin{macrocode}
\cs_new:Npn \CTEX@titlepslabel@set #1
  {
    \cs_if_free:cF { CTEXthe#1 }
      { \protect \@namedef { CTEXthe#1 } { \@nameuse { CTEXthe#1 } } }
  }
\cs_new:Npn \CTEX@titlepslabel@clear #1
  {
    \cs_if_free:cF { CTEXthe#1 }
      { \protect \@namedef { CTEXthe#1 } { } }
  }
%    \end{macrocode}
% \end{macro}
%
% \pkg{titleps} 宏包的功能可以由 \pkg{titlesec} 的选项 \opt{pagestyles} 引入。
%    \begin{macrocode}
\ctex_at_end_package:nn { titlesec }
  { \cs_if_free:NF \ttl@settopmark { \ctex_titleps_hook: } }
\ctex_at_end_package:nn { titleps } { \ctex_titleps_hook: }
%    \end{macrocode}
%
% 除此之外，也可以使用 \pkg{titleps} 提供的命令 \tn{newtitlemark} 来完成：
% \begin{verbatim}
%   \newtitlemark { \CTEXthechapter }
%   \newtitlemark { \CTEXthesection }
% \end{verbatim}
% 但 \tn{newtitlemark} 不包含章节间的层次信息，功能上不及修改内部命令完整。
%
% \changes{v2.4.6}{2016/10/31}{重新初始化 \tn{ifthechapter} 等。}
% \begin{macro}[int]{\ttl@setifthe}
% 使 |\iftheXXX| 等命令在页眉设置中可用。
%    \begin{macrocode}
\ctex_at_end_package:nn { titleps }
  {
    \cs_set_protected:Npn \ttl@setifthe #1
      {
        \exp_args:Nco \cs_set:Npn { ifthe #1 }
          {
            \CTEXifname
              { \protect \@firstoftwo }
              { \protect \@secondoftwo }
          }
      }
    \seq_map_function:NN \c_@@_headings_seq \ttl@setifthe
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{目录标签的宽度}
%
% \begin{macro}{\CTEX@toc@width@n}
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@toc@width@n #1
  {
    \hbox_set:Nn \l_@@_tmp_box {#1}
    \dim_set:Nn \@tempdima
      {
        \dim_max:nn { \@tempdima }
          { \box_wd:N \l_@@_tmp_box + \f@size \p@ / 2 }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5}{2020/01/11}{兼容 \pkg{titletoc} 宏包。}
%
% \begin{macro}{\numberline,\@@_patch_toc_width:n}
% 为 \tn{numberline} 命令打补丁，并兼容 \pkg{tocloft} 和 \pkg{titletoc} 宏包。
%
% 这里需要替换 |#| 本身，因此需要先切换为 other 类。表示参数的 |#| 用
% \cs{c_parameter_token} 代替。
%    \begin{macrocode}
\group_begin:
\char_set_catcode_other:N \#
\use:n
  {
    \group_end:
    \ctex_preto_cmd:NnnTF \numberline { \ExplSyntaxOff }
      { \CTEX@toc@width@n {#1} }
      { }
      { \ctex_patch_failure:N \numberline }
    \cs_new_protected:Npn \@@_patch_toc_width:n \c_parameter_token 1
      {
        \@ifpackageloaded { \c_parameter_token 1 }
          { }
          {
            \ctex_at_end_package:nn { \c_parameter_token 1 }
              {
                \ctex_preto_cmd:NnnTF \numberline
                  { \char_set_catcode_letter:n { 64 } }
                  { \CTEX@toc@width@n {#1} }
                  { }
                  { \ctex_patch_failure:N \numberline }
              }
          }
      }
  }
\@@_patch_toc_width:n { tocloft  }
\@@_patch_toc_width:n { titletoc }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{页眉信息的修改}
%
% \begin{macro}[int]{\ps@headings}
% \changes{v2.4.5}{2016/10/01}{修复补丁失败。}
% \changes{v2.4.7}{2016/12/23}{修复 \cls{ctexrep} 类的 \tn{chaptermark} 汉化错误。}
% \changes{v2.4.11}{2017/09/13}{补充页眉空格。}
%    \begin{macrocode}
%<*article>
\legacy_if:nTF { @twoside }
  {
    \ctex_patch_cmd:Nnn \ps@headings
      { \ifnum \c@secnumdepth > \z@ \thesection \quad \fi }
      { \CTEXifname { \CTEXthesection \quad } { } }
    \ctex_patch_cmd:Nnn \ps@headings
      { \ifnum \c@secnumdepth > \@ne \thesubsection \quad \fi }
      { \CTEXifname { \CTEXthesubsection \quad } { } }
  }
%    \end{macrocode}
% 不知为何，标准文档类此处对 \texttt{secnumdepth} 的判断为 $0$，与 \tn{section} 的层次 $1$ 不符。
%    \begin{macrocode}
  {
    \ctex_patch_cmd:Nnn \ps@headings
      { \ifnum \c@secnumdepth > \m@ne \thesection \quad \fi }
      { \CTEXifname { \CTEXthesection \quad } { } }
  }
%</article>
%<*book|report>
\ctex_patch_cmd:Nnn \ps@headings
  {
%<book>    \ifnum \c@secnumdepth > \m@ne \if@mainmatter
%<report>    \ifnum \c@secnumdepth > \m@ne
      \@chapapp \ \thechapter . ~ \ %
%<report>    \fi
%<book>    \fi \fi
  }
  { \CTEXifname { \CTEXthechapter \quad } { } }
\legacy_if:nT { @twoside }
  {
    \ctex_patch_cmd:Nnn \ps@headings
      { \ifnum \c@secnumdepth > \z@ \thesection . ~ \ \fi }
      { \CTEXifname { \CTEXthesection \quad } { } }
  }
%</book|report>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\f@nch@initialise}
% 这里对 \pkg{fancyhdr} 宏包打补丁。原来 \pkg{fancyhdr} 宏包中使用
% \tn{thesection} 等宏表示页眉中的章节编号，这里改用 \pkg{ctex} 包所用的
% \tn{CTEXthesection} 系列宏。
% \changes{v2.5.6}{2021/01/11}{更新 \pkg{fancyhdr} 宏包的补丁。}
%    \begin{macrocode}
\ctex_at_end_package:nn { fancyhdr }
  {
    \ctex_patch_cmd:Nnn \f@nch@initialise
      { \ifnum \c@secnumdepth > \z@ \thesection \hskip 1em \relax \fi }
      { \CTEXifname { \CTEXthesection \quad } { } }
    \ctex_patch_cmd:Nnn \f@nch@initialise
      { \ifnum \c@secnumdepth > \@ne \thesubsection \hskip 1em \relax \fi }
      { \CTEXifname { \CTEXthesubsection \quad } { } }
    \ctex_patch_cmd:Nnn \f@nch@initialise
      { \ifnum \c@secnumdepth > \m@ne \@chapapp\ \thechapter . ~ \ \fi }
      { \CTEXifname { \CTEXthechapter \quad } { } }
    \ctex_patch_cmd:Nnn \f@nch@initialise
      { \ifnum \c@secnumdepth > \z@ \thesection . ~ \ \fi }
      { \CTEXifname { \CTEXthesection \quad } { } }
    \f@nch@initialise
%    \end{macrocode}
% \pkg{fancyhdr} 的 \opt{headings} 选项会重定义 \tn{ps@headings}，
% 这里也要打补丁。
%    \begin{macrocode}
    \@ifpackagewith { fancyhdr } { headings }
      {
%<*article>
        \legacy_if:nTF { @twoside }
          {
            \ctex_patch_cmd:Nnn \ps@headings
              { \ifnum \c@secnumdepth > \z@ \thesection \quad \fi }
              { \CTEXifname { \CTEXthesection \quad } { } }
            \ctex_patch_cmd:Nnn \ps@headings
              { \ifnum \c@secnumdepth > \@ne \thesubsection \quad \fi }
              { \CTEXifname { \CTEXthesubsection \quad } { } }
          }
          {
            \ctex_patch_cmd:Nnn \ps@headings
              { \ifnum \c@secnumdepth > \z@ \thesection \quad \fi }
              { \CTEXifname { \CTEXthesection \quad } { } }
          }
%</article>
%<*book|report>
        \ctex_patch_cmd:Nnn \ps@headings
          {
%<book>            \ifnum \c@secnumdepth > \m@ne \if@mainmatter
%<report>            \ifnum \c@secnumdepth > \m@ne
              \@chapapp \ \thechapter . ~ \ %
%<report>            \fi
%<book>            \fi \fi
          }
          { \CTEXifname { \CTEXthechapter \quad } { } }
        \legacy_if:nT { @twoside }
          {
            \ctex_patch_cmd:Nnn \ps@headings
              { \ifnum \c@secnumdepth > \z@ \thesection . ~ \ \fi }
              { \CTEXifname { \CTEXthesection \quad } { } }
          }
%</book|report>
      }
      { }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</article|book|report>
%    \end{macrocode}
%
% \subsubsection{\cls{beamer} 标题页模板的修改}
%
%    \begin{macrocode}
%<*beamer>
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOff
%    \end{macrocode}
%
% \changes{v2.4.15}{2019/01/29}{局部指定 \opt{autoindent} 为 \opt{false}，并交换
%   \tn{CTEX@XXX@indent} 与 \tn{CTEX@XXX@format} 的顺序。}
%
% 对应 \tn{partpage}。
%    \begin{macrocode}
\defbeamertemplate*{part page}{CTEX}[1][]{%
  \begingroup
%    \centering
%    {\usebeamerfont{part name}%
%     \usebeamercolor[fg]{part name}\partname~\insertromanpartnumber}
%    \vskip1em\par
    \par \addvspace{\glueexpr\CTEX@part@beforeskip\relax}%
    \CTEX@heading@format@initial
    \CTEX@part@format{%
      \CTEX@indentbox{\CTEX@part@indent}%
      \ifodd \CTEX@part@numbering
        \CTEX@partname \CTEX@part@aftername
      \fi
      \begin{beamercolorbox}[sep=16pt,center,#1]{part title}
%       \usebeamerfont{part title}\insertpart\par
        \CTEX@part@titleformat \insertpart \CTEX@part@aftertitle
      \end{beamercolorbox}}%
    \par \addvspace{\glueexpr\CTEX@part@afterskip\relax}%
  \endgroup}
%    \end{macrocode}
%
% 对应 \tn{sectionpage}。
%    \begin{macrocode}
\defbeamertemplate*{section page}{CTEX}[1][]{%
  \begingroup
%    \centering
%    {\usebeamerfont{section name}%
%     \usebeamercolor[fg]{section name}\sectionname~\insertsectionnumber}
%    \vskip1em\par
    \par \addvspace{\glueexpr\CTEX@section@beforeskip\relax}%
    \CTEX@heading@format@initial
    \CTEX@section@format{%
      \CTEX@indentbox{\CTEX@section@indent}%
      \ifodd \CTEX@section@numbering
        \CTEX@sectionname \CTEX@section@aftername
      \fi
      \begin{beamercolorbox}[sep=12pt,center,#1]{part title}
%       \usebeamerfont{section title}\insertsection\par
        \CTEX@section@titleformat \insertsection \CTEX@section@aftertitle
      \end{beamercolorbox}}%
    \par \addvspace{\glueexpr\CTEX@section@afterskip\relax}%
  \endgroup}
%    \end{macrocode}
%
% 对应 \tn{subsectionpage}。
%    \begin{macrocode}
\defbeamertemplate*{subsection page}{CTEX}[1][]{%
  \begingroup
%    \centering
%    {\usebeamerfont{subsection name}%
%     \usebeamercolor[fg]{subsection name}\subsectionname~\insertsubsectionnumber}
%    \vskip1em\par
    \par \addvspace{\glueexpr\CTEX@subsection@beforeskip\relax}%
    \CTEX@heading@format@initial
    \CTEX@subsection@format{%
      \CTEX@indentbox{\CTEX@subsection@indent}%
      \ifodd \CTEX@subsection@numbering
        \CTEX@subsectionname \CTEX@subsection@aftername
      \fi
      \begin{beamercolorbox}[sep=8pt,center,#1]{part title}
%       \usebeamerfont{subsection title}\insertsubsection\par
        \CTEX@subsection@titleformat \insertsubsection \CTEX@subsection@aftertitle
      \end{beamercolorbox}}%
    \par \addvspace{\glueexpr\CTEX@subsection@afterskip\relax}%
  \endgroup}
%    \end{macrocode}
%
% 将 \cls{beamer} 的默认模板重定向为 \texttt{CTEX} 模板。
%    \begin{macrocode}
\defbeamertemplatealias{part page}{default}{CTEX}
\defbeamertemplatealias{section page}{default}{CTEX}
\defbeamertemplatealias{subsection page}{default}{CTEX}
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
%    \begin{macrocode}
%</beamer>
%    \end{macrocode}
%
% \subsubsection{标题编号和目录的层次设置}
%
% \changes{v2.5.2}{2020/05/06}{新增标题选项 \opt{secnumdepth} 和 \opt{tocdepth}。}
%
% \begin{macro}{secnumdepth, tocdepth}
% \opt{secnumdepth} 在 \cls{beamer} 下无意义。
%    \begin{macrocode}
\ctex_define:n
  {
%<*!beamer>
    secnumdepth           .code:n = \ctex_heading_depth:ne { secnumdepth } {#1} ,
    secnumdepth .value_required:n = true ,
%</!beamer>
    tocdepth              .code:n = \ctex_heading_depth:ne { tocdepth } {#1} ,
    tocdepth    .value_required:n = true
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_heading_depth:nn}
% 注意此处 \tn{setcounter} 的赋值是全局的。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_heading_depth:nn #1#2
  {
    \prop_get:NnNTF \c_@@_heading_level_prop {#2} \l_@@_tmp_tl
      { \setcounter {#1} { \l_@@_tmp_tl } }
      { \setcounter {#1} { \int_eval:n {#2} } }
  }
\cs_generate_variant:Nn \ctex_heading_depth:nn { ne }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}[int]{\c_@@_heading_level_prop}
% 章节层次与名称的对应表。
%    \begin{macrocode}
\prop_const_from_keyval:Nn \c_@@_heading_level_prop
  {
%<*article|beamer>
    part          =  0 ,
%</article|beamer>
%<*book|report>
    part          = -1 ,
    chapter       =  0 ,
%</book|report>
    section       =  1 ,
    subsection    =  2 ,
    subsubsection =  3 ,
    paragraph     =  4 ,
    subparagraph  =  5
  }
%    \end{macrocode}
% \end{variable}
%
% \subsubsection{标签引用数字的汉化}
%
% \begin{macro}[int]{\refstepcounter}
% 对标题进行引用时，设置标签为通过 \opt{number} 选项设置的形式。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@setcurrentlabel@n #1
  {
    \protected@edef \@currentlabel
      {
        \cs_if_exist:cTF { CTEX@the#1 }
          { \exp_args:cc { p@#1 } { CTEX@the#1 } }
          { \exp_not:o { \@currentlabel } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_varioref_hook:}
% 关于标签引用的宏包可能会修改 \tn{refstepcounter}。其中 \pkg{cleveref} 和
% \pkg{hyperref} 宏包都会保存之前的定义，并且它们都要求尽可能晚的被载入，所以
% 对我们上述的修改影响不大。需要注意的是 \pkg{varioref} 宏包，如果它在
% \CTeX{} 之后被载入，我们之前的修改将会被覆盖。
% 较新版 \LaTeX \ 内核已经包含 \tn{labelformat}，可以直接使用。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_varioref_hook:
  {
    \seq_map_inline:Nn \c_@@_headings_seq
      { \ctex_fix_varioref_label:n { ##1 } }
    \ctex_at_end_package:nn { cleveref } { \ctex_cleveref_hook: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ctex_fix_varioref_label:n}
% \pkg{varioref} 宏包的 \tn{labelformat} 实际上是定义一个以 |\the<#1>| 为参数的宏
% |\p@<#1>|。\LaTeX{} 在定义计数器 |<#1>| 时，都会将 |\p@<#1>| 初始化为 \tn{@empty}。
% 如果这个宏非空，说明用户自定义了标签格式，我们就不再修改。这里不能使用
% \cs{exp_args:Nnc}，因为 \texttt{c} 这种展开格式不会将参数放在花括号内。而
% \tn{labelformat} 的定义是
% \begin{verbatim}
%   \def\labelformat#1{\expandafter\def\csname p@#1\endcsname##1}
% \end{verbatim}
% 它的第二个参数必须放在花括号内，否则将会被作为宏的定界符号。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_fix_varioref_label:n #1
  {
    \tl_if_empty:cT { p@#1 }
      { \exp_args:Nne \labelformat {#1} { \exp_not:c { CTEX@the#1 } } }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.3}{2020/06/04}{兼容 \pkg{cleveref}。}
% \changes{v2.5.4}{2020/06/17}{同时兼容 \pkg{cleveref} 和 \pkg{hyperref}。}
% \changes{v2.5.7}{2021/06/04}{同时兼容 \pkg{cleveref} 和 \cls{beamer}。}
%
% \begin{macro}{patch/cleveref}
% \pkg{cleveref} 宏包长期未维护，与较新的 \LaTeX{} 内核和 \pkg{hyperref}
% 存在兼容问题。\CTeX{} 提供了对 \pkg{cleveref} 的补丁，但用户也可以选择
% 关闭它。
%
% 当同时使用 \pkg{hyperref} 和 \pkg{cleveref} 时，|\appendix| 之后的交叉引用
% 类型可能不正确（例如，\texttt{appendix} 退化为 \texttt{chapter}）。
% 这是上游 \LaTeX{} 内核 \texttt{firstaid} 对 \pkg{cleveref} 补丁不完整所致，
% 与 \CTeX{} 无关。可以使用以下方法规避：
% \begin{verbatim}
%   \AddToHook{cmd/appendix/before}{%
%     \crefalias{chapter}{appendix}%
%     \crefalias{section}{subappendix}%
%     \crefalias{subsection}{subsubappendix}%
%     \crefalias{subsubsection}{subsubsubappendix}%
%   }
% \end{verbatim}
%    \begin{macrocode}
\ctex_define:n
  {
    patch / cleveref .bool_set:N = \l_@@_patch_cleveref_bool ,
    patch / cleveref .initial:n = true
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ctex_cleveref_hook:,\@@_cleveref_hook_aux:N}
% 需要将\pkg{cleveref} 包对应命令中 |\p@|\meta{counter} 的参数及时展开，以兼容 \tn{labelformat}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_cleveref_hook:
  {
    \bool_if:NT \l_@@_patch_cleveref_bool
      {
        \@ifpackageloaded { hyperref }
          {
            \@ifpackagewith { hyperref } { implicit = false }
              { }
              { \@@_cleveref_hook_aux:N \H@refstepcounter }
          }
          {
            \@@_cleveref_hook_aux:N \refstepcounter@noarg
            \@@_cleveref_hook_aux:N \refstepcounter@optarg
          }
        \@@_cleveref_hook_aux:N \appendix
      }
  }
\cs_new_protected:Npn \@@_cleveref_hook_aux:N #1
  {
    \ctex_patch_cmd_all:NnnnTF #1
      {
        \ExplSyntaxOff
        \char_set_catcode_letter:n { 64 }
      }
      { \endcsname \csname the }
      { \expandafter \endcsname \csname the }
      { }
      { \ctex_patch_failure:N #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5}{2020/04/19}{应用新内核中的 \tn{labelformat}。}
%
% 如果 \pkg{varioref} 已经被载入，则使用它来设置。
%    \begin{macrocode}
\cs_if_exist:NTF \labelformat
  { \ctex_varioref_hook: }
  {
    \cs_new_eq:NN \CTEX@save@refstepcounter \refstepcounter
    \RenewDocumentCommand \refstepcounter { m }
      {
        \CTEX@save@refstepcounter {#1}
        \CTEX@setcurrentlabel@n {#1}
      }
    \ctex_at_end_package:nn { varioref } { \ctex_varioref_hook: }
  }
%    \end{macrocode}
%
% \subsubsection{载入 \meta{scheme} 文件}
%
%    \begin{macrocode}
\ctex_scheme_input:o { \l_@@_scheme_tl }
%    \end{macrocode}
%
%    \begin{macrocode}
%</class|heading>
%    \end{macrocode}
%
% \subsubsection{\texttt{ctex.sty} 的 \opt{heading} 选项}
%
%    \begin{macrocode}
%<*ctex|ctexheading>
%    \end{macrocode}
%
% \begin{variable}{\c_@@_std_class_tl}
% 用于记录被引入的标准文档类。
%    \begin{macrocode}
\clist_map_inline:nn { article , book , report , beamer }
  {
    \@ifclassloaded {#1}
      { \clist_map_break:n { \tl_const:Nn \c_@@_std_class_tl {#1} } }
      { }
  }
%    \end{macrocode}
% \end{variable}
%
% 若标准文档类被引入，则载入对应的标题定义文件。否则视 \tn{chapter} 是否有定义来
% 引入 \cls{book} 或者 \cls{article}。
%    \begin{macrocode}
\msg_new:nnn { ctex } { not-standard-class }
  {
    None~of~the~standard~document~classes~was~loaded.\\
    Heading~`#1'~is~selected.\\
    ctex~may~not~work~as~expected.
  }
%<ctex>\bool_if:NTF \l_@@_heading_bool
%<ctexheading>\use:n
  {
    \tl_if_exist:NTF \c_@@_std_class_tl
      { \cs_new_eq:NN \c_@@_class_tl \c_@@_std_class_tl }
      {
        \cs_if_exist:NTF \chapter
          {
            \cs_if_exist:NF \if@mainmatter
              { \cs_new_eq:NN \if@mainmatter \tex_iftrue:D }
            \tl_const:Nn \c_@@_class_tl { book }
          }
          { \tl_const:Nn \c_@@_class_tl { article } }
        \msg_warning:nne { ctex } { not-standard-class } { \c_@@_class_tl }
      }
    \ctex_file_input:n { ctex-heading- \c_@@_class_tl .def }
  }
%<ctex>  { \ctex_scheme_input:o { \l_@@_scheme_tl } }
%    \end{macrocode}
%
%    \begin{macrocode}
%</ctex|ctexheading>
%    \end{macrocode}
%
% \subsection{中文字号}
%
%    \begin{macrocode}
%<*class|ctex|ctexsize>
%    \end{macrocode}
%
% \changes{v2.0}{2014/03/08}{将中文字号功能提取到可以独立使用的 \pkg{ctexsize}。}
%
% \begin{macro}{\zihao}
%    \begin{macrocode}
\NewDocumentCommand \zihao { m }
  { \exp_args:Ne \ctex_zihao:n {#1} \tex_ignorespaces:D }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_zihao:n}
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_zihao:n #1
  {
    \prop_get:NnNTF \c_@@_font_size_prop {#1} \l_@@_font_size_tl
      { \exp_after:wN \fontsize \l_@@_font_size_tl \selectfont }
      { \msg_error:nnn { ctex } { fontsize } {#1} }
  }
\msg_new:nnnn { ctex } { fontsize }
  { Undefined~Chinese~font~size~`#1'~in~command~\token_to_str:N \zihao.}
  {
    The~old~font~size~is~used~if~you~continue.\\
    The~available~font~sizes~are~listed~as~follow.\\
    \seq_use:Nnnn \c_@@_font_size_seq { ~and~ } { ,~ } { ,~and~ }.
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{定义中文字号}
%
% \changes{v2.0}{2014/03/08}{中文字号不再采用近似值。}
%
% \begin{variable}{\c_@@_font_size_prop}
% \begin{macro}{\@@_save_font_size:nn}
% \begin{macro}[int]{\ctex_save_font_size:nn}
% 基础行距是字号的 $1.2$ 倍，采用 \hologo{eTeX} 的 scaling 运算得到的结果
% 要比简单的 |1.2\dimexpr| 精确^^A
% \footnote{\url{http://thread.gmane.org/gmane.comp.tex.latex.latex3/3190}}。
%    \begin{macrocode}
\prop_new:N \l_@@_font_size_temp_prop
\seq_new:N  \l_@@_font_size_temp_seq
\cs_new_protected:Npn \@@_save_font_size:nn #1#2
  {
    \prop_put:Nne \l_@@_font_size_temp_prop {#1}
      {
        { \dim_to_decimal:n {#2} }
        { \dim_to_decimal:n { (#2) * 6 / 5 } }
      }
    \seq_put_right:Nn \l_@@_font_size_temp_seq {#1}
  }
\cs_new_eq:NN \ctex_save_font_size:nn \@@_save_font_size:nn
\group_begin:
  \prop_clear:N \l_@@_font_size_temp_prop
  \seq_clear:N  \l_@@_font_size_temp_seq
  \str_case:onF { \g_@@_font_size_system_tl }
    {
      { word }
      {
        \clist_map_inline:nn
          {
            {  8 } { 5    bp } ,
            {  7 } { 5.5  bp } ,
            { -6 } { 6.5  bp } ,
            {  6 } { 7.5  bp } ,
            { -5 } { 9    bp } ,
            {  5 } { 10.5 bp } ,
            { -4 } { 12   bp } ,
            {  4 } { 14   bp } ,
            { -3 } { 15   bp } ,
            {  3 } { 16   bp } ,
            { -2 } { 18   bp } ,
            {  2 } { 22   bp } ,
            { -1 } { 24   bp } ,
            {  1 } { 26   bp } ,
            { -0 } { 36   bp } ,
            {  0 } { 42   bp }
          }
          { \@@_save_font_size:nn #1 }
      }
      { letterpress }
      {
        \clist_map_inline:nn
          {
            {  8 } { 4    bp } ,
            {  7 } { 5.25 bp } ,
            { -6 } { 7.5  bp } ,
            {  6 } { 8    bp } ,
            { -5 } { 9    bp } ,
            {  5 } { 10.5 bp } ,
            { -4 } { 12   bp } ,
            {  4 } { 14   bp } ,
            { -3 } { 15   bp } ,
            {  3 } { 16   bp } ,
            { -2 } { 18   bp } ,
            {  2 } { 21   bp } ,
            { -1 } { 24   bp } ,
            {  1 } { 28   bp } ,
            { -0 } { 36   bp } ,
            {  0 } { 42   bp }
          }
          { \@@_save_font_size:nn #1 }
      }
    }
    {
      \file_if_exist:nTF { ctex-fontsize- \g_@@_font_size_system_tl .def }
        {
          \ctex_file_input:n
            { ctex-fontsize- \g_@@_font_size_system_tl .def }
        }
        {
          \msg_error:nne { ctex } { fontsize-system-not-found }
            { \g_@@_font_size_system_tl }
          \clist_map_inline:nn
            {
              {  8 } { 5    bp } ,
              {  7 } { 5.5  bp } ,
              { -6 } { 6.5  bp } ,
              {  6 } { 7.5  bp } ,
              { -5 } { 9    bp } ,
              {  5 } { 10.5 bp } ,
              { -4 } { 12   bp } ,
              {  4 } { 14   bp } ,
              { -3 } { 15   bp } ,
              {  3 } { 16   bp } ,
              { -2 } { 18   bp } ,
              {  2 } { 22   bp } ,
              { -1 } { 24   bp } ,
              {  1 } { 26   bp } ,
              { -0 } { 36   bp } ,
              {  0 } { 42   bp }
            }
            { \@@_save_font_size:nn #1 }
        }
    }
  \exp_args:NNe \prop_const_from_keyval:Nn \c_@@_font_size_prop
    { \prop_to_keyval:N \l_@@_font_size_temp_prop }
  \exp_args:NNe \seq_const_from_clist:Nn \c_@@_font_size_seq
    { \seq_use:Nn \l_@@_font_size_temp_seq { , } }
\group_end:
\msg_new:nnnn { ctex } { fontsize-system-not-found }
  {
    CTeX~font~size~system~`#1'~could~not~be~found.
    \\ The~`word'~system~will~be~used~instead.
  }
  { You~may~need~to~create~`ctex-fontsize-#1.def'. }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{variable}
%
% \begin{macro}[int]{\ctex_declare_math_sizes:nnnn}
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_declare_math_sizes:nnnn #1#2#3#4
  {
    \@@_get_font_sizes:Nn \l_@@_font_size_tl { {#1} {#2} {#3} {#4} }
    \exp_after:wN \DeclareMathSizes \l_@@_font_size_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_get_font_sizes:Nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_get_font_sizes:Nn #1#2
  {
    \tl_clear:N #1
    \tl_map_inline:nn {#2}
      {
        \prop_get:NnNTF \c_@@_font_size_prop {##1} \l_@@_tmp_tl
          { \tl_put_right:Ne #1 { { \tl_head:N \l_@@_tmp_tl } } }
          { \tl_put_right:Ne #1 { { \dim_to_decimal:n { ##1 } } } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\clist_map_inline:nn
  {
    {  8 }{  8 }{ 5pt }{ 5pt } ,
    {  7 }{  7 }{ 5pt }{ 5pt } ,
    { -6 }{ -6 }{ 5pt }{ 5pt } ,
    {  6 }{  6 }{ 5pt }{ 5pt } ,
    { -5 }{ -5 }{ 6pt }{ 5pt } ,
    {  5 }{  5 }{ 7pt }{ 5pt } ,
    { -4 }{ -4 }{ 8pt }{ 6pt } ,
    {  4 }{  4 }{  5 }{  6 } ,
    { -3 }{ -3 }{ -4 }{ -5 } ,
    {  3 }{  3 }{  4 }{  5 } ,
    { -2 }{ -2 }{ -3 }{ -4 } ,
    {  2 }{  2 }{  3 }{  4 } ,
    { -1 }{ -1 }{ -2 }{ -3 } ,
    {  1 }{  1 }{  2 }{  3 } ,
    { -0 }{ -0 }{ -1 }{ -2 } ,
    {  0 }{  0 }{  1 }{  2 }
  }
  { \ctex_declare_math_sizes:nnnn #1 }
%    \end{macrocode}
%
% \subsubsection{修改默认字号大小}
%
% \begin{macro}[int]{\ctex_set_font_size:Nnn}
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_set_font_size:Nnn #1#2#3
  {
    \prop_get:NnNTF \c_@@_font_size_prop {#2} \l_@@_font_size_tl
      { \exp_after:wN \@@_set_font_size:nnNn \l_@@_font_size_tl #1 {#3} }
      { \msg_error:nnn { ctex } { fontsize } {#2} }
  }
\cs_new_protected:Npn \@@_set_font_size:nnNn #1#2#3#4
  { \cs_set_protected:Npn #3 { \@setfontsize #3 {#1} {#2} #4 } }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\int_case:nn { \g_@@_font_size_int }
  {
    { 0 } { \file_input:n { ctex-c5size.clo } }
    { 1 } { \file_input:n { ctex-cs4size.clo } }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</class|ctex|ctexsize>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*c5size>
\ctex_set_font_size:Nnn \normalsize { 5 }
  {
    \abovedisplayskip 10\p@ \@plus2\p@ \@minus5\p@
    \abovedisplayshortskip \z@ \@plus3\p@
    \belowdisplayshortskip 6\p@ \@plus3\p@ \@minus3\p@
    \belowdisplayskip \abovedisplayskip
    \let\@listi\@listI
  }
\ctex_set_font_size:Nnn \small { -5 }
  {
    \abovedisplayskip 8.5\p@ \@plus3\p@ \@minus4\p@
    \abovedisplayshortskip \z@ \@plus2\p@
    \belowdisplayshortskip 4\p@ \@plus2\p@ \@minus2\p@
    \def\@listi{\leftmargin\leftmargini
                \topsep 4\p@ \@plus2\p@ \@minus2\p@
                \parsep 2\p@ \@plus\p@ \@minus\p@
                \itemsep \parsep}
    \belowdisplayskip \abovedisplayskip
  }
\ctex_set_font_size:Nnn \footnotesize { 6 }
  {
    \abovedisplayskip 6\p@ \@plus2\p@ \@minus4\p@
    \abovedisplayshortskip \z@ \@plus\p@
    \belowdisplayshortskip 3\p@ \@plus\p@ \@minus2\p@
    \def\@listi{\leftmargin\leftmargini
                \topsep 3\p@ \@plus\p@ \@minus\p@
                \parsep 2\p@ \@plus\p@ \@minus\p@
                \itemsep \parsep}
    \belowdisplayskip \abovedisplayskip
  }
\ctex_set_font_size:Nnn \scriptsize { -6 } { }
\ctex_set_font_size:Nnn \tiny  {  7 } { }
\ctex_set_font_size:Nnn \large { -4 } { }
\ctex_set_font_size:Nnn \Large { -3 } { }
\ctex_set_font_size:Nnn \LARGE { -2 } { }
\ctex_set_font_size:Nnn \huge  {  2 } { }
\ctex_set_font_size:Nnn \Huge  {  1 } { }
%</c5size>
%<*cs4size>
\ctex_set_font_size:Nnn \normalsize { -4 }
  {
    \abovedisplayskip 12\p@ \@plus3\p@ \@minus7\p@
    \abovedisplayshortskip \z@ \@plus3\p@
    \belowdisplayshortskip 6.5\p@ \@plus3.5\p@ \@minus3\p@
    \belowdisplayskip \abovedisplayskip
    \let\@listi\@listI
  }
\ctex_set_font_size:Nnn \small { 5 }
  {
    \abovedisplayskip 11\p@ \@plus3\p@ \@minus6\p@
    \abovedisplayshortskip \z@ \@plus3\p@
    \belowdisplayshortskip 6.5\p@ \@plus3.5\p@ \@minus3\p@
    \def\@listi{\leftmargin\leftmargini
                \topsep 9\p@ \@plus3\p@ \@minus5\p@
                \parsep 4.5\p@ \@plus2\p@ \@minus\p@
                \itemsep \parsep}
    \belowdisplayskip \abovedisplayskip
  }
\ctex_set_font_size:Nnn \footnotesize { -5 }
  {
    \abovedisplayskip 10\p@ \@plus2\p@ \@minus5\p@
    \abovedisplayshortskip \z@ \@plus3\p@
    \belowdisplayshortskip 6\p@ \@plus3\p@ \@minus3\p@
    \def\@listi{\leftmargin\leftmargini
                \topsep 6\p@ \@plus2\p@ \@minus2\p@
                \parsep 3\p@ \@plus2\p@ \@minus\p@
                \itemsep \parsep}
    \belowdisplayskip \abovedisplayskip
  }
\ctex_set_font_size:Nnn \scriptsize { 6 } { }
\ctex_set_font_size:Nnn \tiny  { -6 } { }
\ctex_set_font_size:Nnn \large { -3 } { }
\ctex_set_font_size:Nnn \Large { -2 } { }
\ctex_set_font_size:Nnn \LARGE {  2 } { }
\ctex_set_font_size:Nnn \huge  { -1 } { }
\ctex_set_font_size:Nnn \Huge  {  1 } { }
%</cs4size>
%    \end{macrocode}
%
%    \begin{macrocode}
%<ctexsize>\normalsize
%    \end{macrocode}
%
%    \begin{macrocode}
%<*class|ctex>
%    \end{macrocode}
%
% \subsection{更新行距}
%
% \cs{l_@@_line_spread_fp} 被设置了才有必要更新行距和 \tn{footnotesep}。
%    \begin{macrocode}
\fp_if_nan:nF { \l_@@_line_spread_fp }
  {
    \exp_args:Ne \linespread { \fp_use:N \l_@@_line_spread_fp }
%    \end{macrocode}
%
% \changes{v2.0}{2014/04/23}{调整 \tn{footnotesep} 的大小，以适合行距的变化。}
%
% \begin{variable}[int]{\footnotesep}
% 我们调整了行距，可能导致脚注的间距与行距不协调，需要调整 \tn{footnotesep}。标准
% 文档类对 \tn{footnotesep} 的设置是，字体大小为 \tn{footnotesize} 时 \tn{strutbox}
% 的高度（默认值是 |.7\baselineskip|）。我们沿用这个设置方法，只需要更新具体的大小。
%    \begin{macrocode}
    \group_begin: \footnotesize \exp_args:NNNo \group_end:
    \dim_set:Nn \footnotesep { \dim_use:N \box_ht:N \strutbox }
  }
%    \end{macrocode}
% \end{variable}
%
% 激活默认字体大小，更新行距、\tn{parindent} 和 \tn{CJKglue}。
%    \begin{macrocode}
\normalsize
%    \end{macrocode}
%
% \subsection{其他功能}
%
% \begin{macro}{\CTeX}
% \changes{v2.4.12}{2017/12/05}{不依赖 \tn{ifincsname}。}
% \file{ctex-faq.sty} 中的定义是
% \begin{verbatim}
%   \DeclareRobustCommand\CTeX{$\mathbb{C}$\kern-.05em\TeX}
% \end{verbatim}
% 然而 \tn{mathbb} 未必有定义，这里就不采用它了，只定义最简单的形式。
% \CTeX{} 可以直接用在 PDF 书签中。
%    \begin{macrocode}
\NewDocumentCommand \CTeX { }
  { C \TeX }
\ctex_at_end_package:nn { hyperref }
  { \pdfstringdefDisableCommands { \tl_set:Nn \CTeX { CTeX } } }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/28}{\opt{captiondelimiter} 是过时选项。}
% \begin{macro}{captiondelimiter}
% 过时选项。
%    \begin{macrocode}
\ctex_define:n
  {
    captiondelimiter .code:n =
      {
        \ctex_deprecated_option:n
          { You~can~load~the~package~`caption'~to~get~its~functionality. }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2014/03/09}
% {解决 \pkg{etoolbox} 与 \pkg{breqn} 关于 \tn{end} 的冲突。}
% \changes{v2.2}{2015/06/23}{删去 \pkg{etoolbox} 与 \pkg{breqn} 的兼容补丁。}
%
% \subsection{载入中文字库}
%
% \begin{macro}[int]{\ctex_fontset_error:n}
% 字库不可用时给出紧急错误信息，停止读取定义文件。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_fontset_error:n #1
  { \msg_critical:nnn { ctex } { fontset-unavailable } {#1} }
\msg_new:nnn { ctex } { fontset-unavailable }
  { CTeX~fontset~`#1'~is~unavailable~in~current~mode. }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_fontset_case:nnn}
% $3$ 个参数依次为 \pdfTeX、\upTeX\ 和 \XeTeX/\LuaTeX。
%    \begin{macrocode}
\cs_new:Npx \ctex_fontset_case:nnn #1#2#3
  {
    \sys_if_engine_pdftex:TF
      {#1}
      { \sys_if_engine_uptex:TF {#2} {#3} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_fontset_case:nnnn}
% $4$ 个参数依次为 \pdfTeX（生成 PDF）、\pdfTeX（生成 DVI）、\upTeX 和
% \XeTeX/\LuaTeX。
%    \begin{macrocode}
\cs_new:Npx \ctex_fontset_case:nnnn #1#2#3#4
  {
    \sys_if_engine_pdftex:TF
      { \sys_if_output_pdf:TF   {#1} {#2} }
      { \sys_if_engine_uptex:TF {#3} {#4} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_detect_platform:}
% 根据操作系统判断默认字体配置。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_detect_platform:
  {
    \sys_if_platform_windows:TF
      { \tl_gset:Nn \g_@@_fontset_tl { windows } }
      {
        \ctex_if_platform_macos:TF
          { \tl_gset:Nn \g_@@_fontset_tl { mac    } }
          { \tl_gset:Nn \g_@@_fontset_tl { fandol } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_if_platform_macos:TF}
% \changes{v2.1}{2015/06/17}{改用 \file{/Library/Fonts/Songti.ttc} 为特征文件。}
% \changes{v2.5}{2019/10/25}{改用 \file{/System/Library/Fonts/Menlo.ttc}
%   为特征文件。}
% 以特定字体判断 macOS 系统。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_if_platform_macos:TF
  { \file_if_exist:nTF { /System/Library/Fonts/Menlo.ttc } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_load_fontset:}
% 如果用户没有指定字体，则探测操作系统，载入相应的字体配置。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_load_fontset:
  {
    \tl_if_empty:NTF \g_@@_fontset_tl
      { \ctex_detect_platform: }
      {
        \bool_lazy_or:nnTF
          { \str_if_eq_p:on { \g_@@_fontset_tl } { windowsnew } }
          { \str_if_eq_p:on { \g_@@_fontset_tl } { windowsold } }
          {
            \msg_warning:nnee { ctex } { deprecated-fontset }
              { \g_@@_fontset_tl } { windows }
            \tl_gset:Nn \g_@@_fontset_tl { windows }
          }
          {
            \file_if_exist:nF { ctex-fontset- \g_@@_fontset_tl .def }
              {
                \use:e
                  {
                    \ctex_detect_platform:
                    \msg_error:nnee { ctex } { fontset-not-found }
                      { \g_@@_fontset_tl } { \exp_not:N \g_@@_fontset_tl }
                  }
              }
          }
      }
    \ctex_file_input:n { ctex-fontset- \g_@@_fontset_tl .def }
  }
\msg_new:nnn { ctex } { deprecated-fontset }
  { CTeX~fontset~`#1'~is~deprecated.\\ Fontset~`#2'~will~be~used~instead. }
\msg_new:nnnn { ctex } { fontset-not-found }
  { CTeX~fontset~`#1'~could~not~be~found.\\ Fontset~`#2'~will~be~used~instead. }
  { You~may~run~`mktexlsr'~firstly. }
\@onlypreamble \ctex_load_fontset:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{fontset}
% 在导言区通过 \tn{ctexset} 载入中文字库的选项。
%    \begin{macrocode}
\ctex_define:n
  {
    fontset .code:n =
      {
        \ctex_if_preamble:TF
          {
            \str_if_eq:eeTF {#1} { none }
              { \msg_warning:nnn { ctex } { invalid-value } {#1} }
              {
                \str_if_eq:onTF { \g_@@_fontset_tl } { none }
                  {
                    \tl_gset:Ne \g_@@_fontset_tl {#1}
                    \ctex_load_fontset:
                  }
                  {
                    \msg_error:nnee { ctex } { fontset-loaded }
                      { \g_@@_fontset_tl } {#1}
                  }
              }
          }
          { \msg_error:nn { ctex } { fontset-only-preamble } }
      }
  }
\msg_new:nnnn { ctex } { fontset-loaded }
  {
    CTeX~fontset~`#1'~has~been~loaded.
    \str_if_eq:nnF {#1} {#2} { \\ Fontset~`#2'~will~be~ignored. }
  }
  { Only~one~fontset~can~be~loaded~in~the~preamble. }
\msg_new:nnn { ctex } { fontset-only-preamble }
  { The~`fontset'~option~can~be~used~only~in~preamble. }
%    \end{macrocode}
% \end{macro}
%
% 载入中文字库。
%    \begin{macrocode}
\str_if_eq:onF { \g_@@_fontset_tl } { none }
  { \ctex_load_fontset: }
%    \end{macrocode}
%
% \subsection{宏包配置文件}
%
% \subsubsection{\texttt{ctex.cfg}}
%
%    \begin{macrocode}
\ctex_at_end:n { \ctex_file_input:n { ctex.cfg } }
%    \end{macrocode}
%
%    \begin{macrocode}
%</class|ctex>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}
%
% \end{implementation}
