<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">% \iffalse meta-comment
% !TeX program  = XeLaTeX
% !TeX encoding = UTF-8
%
% Copyright (C) 2003--2022
% 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, either
% version 1.3c of this license or (at your option) any later
% version. This version of this license is in
%    http://www.latex-project.org/lppl/lppl-1-3c.txt
% and the latest version of this license is in
%    http://www.latex-project.org/lppl.txt
% and version 1.3 or later is part of all distributions of
% LaTeX version 2005/12/01 or later.
%
% This work has the LPPL maintenance status "maintained".
%
% --------------------------------------------------------------------------
%
%&lt;*internal&gt;
\iffalse
%&lt;/internal&gt;
%&lt;*readme&gt;
ctex
====

`ctex` is a collection of macro packages and document classes
for LaTeX Chinese typesetting.

Authors and Contributors
------------------------

* Wu Lingyun &lt;aloft@ctex.org&gt;
* Jiang Jiang &lt;gzjjgod@gmail.com&gt;
* Wang Yue &lt;yuleopen@gmail.com&gt;
* Liu Haiyang &lt;leoliu.pku@gmail.com&gt;
* Li Yanrui &lt;liyanrui.m2@gmail.com&gt;
* Chen Zhichu &lt;zhichu.chen@gmail.com&gt;
* Li Qing &lt;sobenlee@gmail.com&gt;
* Liam Huang &lt;liamhuang0205@gmail.com&gt;
* Zeng Xiangdong &lt;xdzeng96@gmail.com&gt;
* Li Zeping &lt;zepinglee@gmail.com&gt;
* Zhou Yukai &lt;muzimuzhi@gmail.com&gt;
* Zhang Ruixi &lt;ruixizhang42@gmail.com&gt;

Contributing
------------

This package is a part of the [ctex-kit](https://github.com/CTeX-org/ctex-kit) project.

Issues and pull requests are welcome.

Copyright and Licence
---------------------

    Copyright (C) 2003--2022
    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, either
    version 1.3c of this license or (at your option) any later
    version. This version of this license is in
       http://www.latex-project.org/lppl/lppl-1-3c.txt
    and the latest version of this license is in
       http://www.latex-project.org/lppl.txt
    and version 1.3 or later is part of all distributions of
    LaTeX version 2005/12/01 or later.

    This work has the LPPL maintenance status "maintained".

    This package consists of the files ctex.dtx,
                                       ctxdoc.cls,
                                       ctxdocstrip.tex,
                                       ctex-zhconv.lua,
                                       ctex-zhconv-make.lua,
                 and the derived files ctex.pdf,
                                       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,
                                       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-name-gbk.cfg,
                                       ctex-name-utf8.cfg,
                                       ctex.cfg,
                                       ctexopts.cfg,
                                       ctexbackend.cfg,
                                       ctex-engine-pdftex.def,
                                       ctex-engine-xetex.def,
                                       ctex-engine-luatex.def,
                                       ctex-engine-aptex.def,
                                       ctex-engine-uptex.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,
                                       ctex-fontset-adobe.def,
                                       ctex-fontset-fandol.def,
                                       ctex-fontset-founder.def,
                                       ctex-fontset-mac.def,
                                       ctex-fontset-macnew.def,
                                       ctex-fontset-macold.def,
                                       ctex-fontset-ubuntu.def,
                                       ctex-fontset-windows.def,
                                       ctexspa.def,
                                       ctexpunct.spa,
                                       ctex-spa-make.tex,
                                       ctex-spa-macro.tex,
                                       ctex-zhmap-adobe.tex,
                                       ctex-zhmap-fandol.tex,
                                       ctex-zhmap-founder.tex,
                                       ctex-zhmap-mac.tex,
                                       ctex-zhmap-ubuntu.tex,
                                       ctex-zhmap-windows.tex,
                                       ctex-zhconv-index.lua,
                                       translator-theorem-dictionary-ChineseGBK.dict,
                                       translator-theorem-dictionary-ChineseUTF8.dict, and
                                       README.md (this file).
%&lt;/readme&gt;
%&lt;*internal&gt;
\fi
\begingroup
  \def\temp{LaTeX2e}
\expandafter\endgroup\ifx\temp\fmtname\else
\csname fi\endcsname
%&lt;/internal&gt;
%&lt;*install&gt;

\input ctxdocstrip %

\preamble

    Copyright (C) 2003--2022
    CTEX.ORG and any individual authors listed in the documentation.
---------------------------------------------------------------------

    This work may be distributed and/or modified under the
    conditions of the LaTeX Project Public License, either
    version 1.3c of this license or (at your option) any later
    version. This version of this license is in
       http://www.latex-project.org/lppl/lppl-1-3c.txt
    and the latest version of this license is in
       http://www.latex-project.org/lppl.txt
    and version 1.3 or later is part of all distributions of
    LaTeX version 2005/12/01 or later.

    This work has the LPPL maintenance status "maintained".

---------------------------------------------------------------------

\endpreamble
\postamble

    This package consists of the files ctex.dtx,
                                       ctxdoc.cls,
                                       ctxdocstrip.tex,
                                       ctex-zhconv.lua,
                                       ctex-zhconv-make.lua,
                 and the derived files ctex.pdf,
                                       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,
                                       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-name-gbk.cfg,
                                       ctex-name-utf8.cfg,
                                       ctex.cfg,
                                       ctexopts.cfg,
                                       ctexbackend.cfg,
                                       ctex-engine-pdftex.def,
                                       ctex-engine-xetex.def,
                                       ctex-engine-luatex.def,
                                       ctex-engine-aptex.def,
                                       ctex-engine-uptex.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,
                                       ctex-fontset-adobe.def,
                                       ctex-fontset-fandol.def,
                                       ctex-fontset-founder.def,
                                       ctex-fontset-mac.def,
                                       ctex-fontset-macnew.def,
                                       ctex-fontset-macold.def,
                                       ctex-fontset-ubuntu.def,
                                       ctex-fontset-windows.def,
                                       ctexspa.def,
                                       ctexpunct.spa,
                                       ctex-spa-make.tex,
                                       ctex-spa-macro.tex,
                                       ctex-zhmap-adobe.tex,
                                       ctex-zhmap-fandol.tex,
                                       ctex-zhmap-founder.tex,
                                       ctex-zhmap-mac.tex,
                                       ctex-zhmap-ubuntu.tex,
                                       ctex-zhmap-windows.tex,
                                       ctex-zhconv-index.lua,
                                       translator-theorem-dictionary-ChineseGBK.dict,
                                       translator-theorem-dictionary-ChineseUTF8.dict, and
                                       README.md.
\endpostamble

\generate
  {
    \usedir{tex/latex/ctex}
    \file{ctex.sty}                        {\from{\jobname.dtx}{style,ctex}}
    \file{ctexsize.sty}                    {\from{\jobname.dtx}{style,ctexsize}}
    \file{ctexheading.sty}                 {\from{\jobname.dtx}{style,ctexheading}}
    \file{ctexart.cls}                     {\from{\jobname.dtx}{class,article}}
    \file{ctexbook.cls}                    {\from{\jobname.dtx}{class,book}}
    \file{ctexrep.cls}                     {\from{\jobname.dtx}{class,report}}
    \file{ctexbeamer.cls}                  {\from{\jobname.dtx}{class,beamer}}
    \usepostamble\emptypostamble
    \file{ctexcap.sty}                     {\from{\jobname.dtx}{ctexcap}}
    \file{ctexhook.sty}                    {\from{\jobname.dtx}{ctexhook}}
    \file{ctexpatch.sty}                   {\from{\jobname.dtx}{ctexpatch}}
    \file{ctex-c5size.clo}                 {\from{\jobname.dtx}{c5size}}
    \file{ctex-cs4size.clo}                {\from{\jobname.dtx}{cs4size}}
    \file{ctex-heading-article.def}        {\from{\jobname.dtx}{heading,article}}
    \file{ctex-heading-book.def}           {\from{\jobname.dtx}{heading,book}}
    \file{ctex-heading-report.def}         {\from{\jobname.dtx}{heading,report}}
    \file{ctex-heading-beamer.def}         {\from{\jobname.dtx}{heading,beamer}}
    \file{ctex-scheme-plain.def}           {\from{\jobname.dtx}{scheme,generic,plain}}
    \file{ctex-scheme-plain-article.def}   {\from{\jobname.dtx}{scheme,article,plain}}
    \file{ctex-scheme-plain-book.def}      {\from{\jobname.dtx}{scheme,book,plain}}
    \file{ctex-scheme-plain-report.def}    {\from{\jobname.dtx}{scheme,report,plain}}
    \file{ctex-scheme-plain-beamer.def}    {\from{\jobname.dtx}{scheme,beamer,plain}}
    \file{ctex-scheme-chinese.def}         {\from{\jobname.dtx}{scheme,generic,chinese}}
    \file{ctex-scheme-chinese-article.def} {\from{\jobname.dtx}{scheme,article,chinese}}
    \file{ctex-scheme-chinese-book.def}    {\from{\jobname.dtx}{scheme,book,chinese}}
    \file{ctex-scheme-chinese-report.def}  {\from{\jobname.dtx}{scheme,report,chinese}}
    \file{ctex-scheme-chinese-beamer.def}  {\from{\jobname.dtx}{scheme,beamer,chinese}}
 \ctxfile{GBK}{ctex-name-gbk.cfg}          {\from{\jobname.dtx}{name,GBK}}
    \file{ctex-name-utf8.cfg}              {\from{\jobname.dtx}{name,UTF8}}
    \file{ctex.cfg}                        {\from{\jobname.dtx}{config}}
    \file{ctexopts.cfg}                    {\from{\jobname.dtx}{ctexopts}}
    \file{ctexbackend.cfg}                 {\from{\jobname.dtx}{backend}}
    \file{ctex-engine-pdftex.def}          {\from{\jobname.dtx}{pdftex}}
    \file{ctex-engine-xetex.def}           {\from{\jobname.dtx}{xetex}}
    \file{ctex-engine-luatex.def}          {\from{\jobname.dtx}{luatex}}
    \file{ctex-engine-aptex.def}           {\from{\jobname.dtx}{aptex}}
    \file{ctex-engine-uptex.def}           {\from{\jobname.dtx}{uptex}}
    \file{c19rm.fd}                        {\from{\jobname.dtx}{fd,rm,c19}}
    \file{c19sf.fd}                        {\from{\jobname.dtx}{fd,sf,c19}}
    \file{c19tt.fd}                        {\from{\jobname.dtx}{fd,tt,c19}}
    \file{c70rm.fd}                        {\from{\jobname.dtx}{fd,rm,c70}}
    \file{c70sf.fd}                        {\from{\jobname.dtx}{fd,sf,c70}}
    \file{c70tt.fd}                        {\from{\jobname.dtx}{fd,tt,c70}}
    \file{jy2zhrm.fd}                      {\from{\jobname.dtx}{fd,rm,jy2}}
    \file{jy2zhsf.fd}                      {\from{\jobname.dtx}{fd,sf,jy2}}
    \file{jy2zhtt.fd}                      {\from{\jobname.dtx}{fd,tt,jy2}}
    \file{jt2zhrm.fd}                      {\from{\jobname.dtx}{fd,rm,jt2}}
    \file{jt2zhsf.fd}                      {\from{\jobname.dtx}{fd,sf,jt2}}
    \file{jt2zhtt.fd}                      {\from{\jobname.dtx}{fd,tt,jt2}}
    \file{ctex-fontset-adobe.def}          {\from{\jobname.dtx}{fontset,adobe}}
    \file{ctex-fontset-fandol.def}         {\from{\jobname.dtx}{fontset,fandol}}
    \file{ctex-fontset-founder.def}        {\from{\jobname.dtx}{fontset,founder}}
    \file{ctex-fontset-mac.def}            {\from{\jobname.dtx}{fontset,mac}}
    \file{ctex-fontset-macnew.def}         {\from{\jobname.dtx}{fontset,macnew}}
    \file{ctex-fontset-macold.def}         {\from{\jobname.dtx}{fontset,macold}}
    \file{ctex-fontset-ubuntu.def}         {\from{\jobname.dtx}{fontset,ubuntu}}
    \file{ctex-fontset-windows.def}        {\from{\jobname.dtx}{fontset,windows}}
 \ctxfile{GBK}{translator-theorem-dictionary-ChineseGBK.dict}
                                           {\from{\jobname.dtx}{dict,theorem,GBK}}
    \file{translator-theorem-dictionary-ChineseUTF8.dict}
                                           {\from{\jobname.dtx}{dict,theorem,UTF8}}
    \file{ctexspa.def}                     {\from{\jobname.dtx}{ctexspa}
                                            \from{ctexpunct.spa}{}}
    \usedir{tex/generic/ctex}
    \file{ctex-spa-make.tex}               {\from{\jobname.dtx}{spa,make}}
    \file{ctex-spa-macro.tex}              {\from{\jobname.dtx}{spa,macro}}
    \file{ctex-zhmap-adobe.tex}            {\from{\jobname.dtx}{zhmap,adobe}}
    \file{ctex-zhmap-fandol.tex}           {\from{\jobname.dtx}{zhmap,fandol}}
    \file{ctex-zhmap-founder.tex}          {\from{\jobname.dtx}{zhmap,founder}}
    \file{ctex-zhmap-mac.tex}              {\from{\jobname.dtx}{zhmap,mac}}
    \file{ctex-zhmap-ubuntu.tex}           {\from{\jobname.dtx}{zhmap,ubuntu}}
    \file{ctex-zhmap-windows.tex}          {\from{\jobname.dtx}{zhmap,windows}}
%&lt;/install&gt;
%&lt;*internal&gt;
    \usedir{source/latex/ctex}
    \file{\jobname.ins}                    {\from{\jobname.dtx}{install}}
%&lt;/internal&gt;
%&lt;*install&gt;
    \nopreamble\nopostamble
    \usedir{doc/latex/ctex}
    \file{README.md}                       {\from{\jobname.dtx}{readme}}
  }

\catcode32=12\space

\Msg{*************************************************************}
\Msg{*                                                           *}
\Msg{* To finish the installation you have to move the following *}
\Msg{* file into proper directories searched by TeX:             *}
\Msg{*                                                           *}
\Msg{* The recommended directory is TDS:tex/latex/ctex           *}
\Msg{*                                                           *}
\Msg{*     ctex.sty                                              *}
\Msg{*     ctexsize.sty                                          *}
\Msg{*     ctexheading.sty                                       *}
\Msg{*     ctexart.cls                                           *}
\Msg{*     ctexbook.cls                                          *}
\Msg{*     ctexrep.cls                                           *}
\Msg{*     ctexbeamer.cls                                        *}
\Msg{*     ctexcap.sty                                           *}
\Msg{*     ctexhook.sty                                          *}
\Msg{*     ctexpatch.sty                                         *}
\Msg{*     ctex-c5size.clo                                       *}
\Msg{*     ctex-cs4size.clo                                      *}
\Msg{*     ctex-heading-article.def                              *}
\Msg{*     ctex-heading-book.def                                 *}
\Msg{*     ctex-heading-report.def                               *}
\Msg{*     ctex-heading-beamer.def                               *}
\Msg{*     ctex-scheme-plain.def                                 *}
\Msg{*     ctex-scheme-plain-article.def                         *}
\Msg{*     ctex-scheme-plain-book.def                            *}
\Msg{*     ctex-scheme-plain-report.def                          *}
\Msg{*     ctex-scheme-plain-beamer.def                          *}
\Msg{*     ctex-scheme-chinese.def                               *}
\Msg{*     ctex-scheme-chinese-article.def                       *}
\Msg{*     ctex-scheme-chinese-book.def                          *}
\Msg{*     ctex-scheme-chinese-report.def                        *}
\Msg{*     ctex-scheme-chinese-beamer.def                        *}
\Msg{*     ctex-name-gbk.cfg                                     *}
\Msg{*     ctex-name-utf8.cfg                                    *}
\Msg{*     ctex.cfg                                              *}
\Msg{*     ctexopts.cfg                                          *}
\Msg{*     ctexbackend.cfg                                       *}
\Msg{*     ctex-engine-pdftex.def                                *}
\Msg{*     ctex-engine-xetex.def                                 *}
\Msg{*     ctex-engine-luatex.def                                *}
\Msg{*     ctex-engine-aptex.def                                 *}
\Msg{*     ctex-engine-uptex.def                                 *}
\Msg{*     c19rm.fd                                              *}
\Msg{*     c19sf.fd                                              *}
\Msg{*     c19tt.fd                                              *}
\Msg{*     c70rm.fd                                              *}
\Msg{*     c70sf.fd                                              *}
\Msg{*     c70tt.fd                                              *}
\Msg{*     jy2zhrm.fd                                            *}
\Msg{*     jy2zhsf.fd                                            *}
\Msg{*     jy2zhtt.fd                                            *}
\Msg{*     jt2zhrm.fd                                            *}
\Msg{*     jt2zhsf.fd                                            *}
\Msg{*     jt2zhtt.fd                                            *}
\Msg{*     ctex-fontset-adobe.def                                *}
\Msg{*     ctex-fontset-fandol.def                               *}
\Msg{*     ctex-fontset-founder.def                              *}
\Msg{*     ctex-fontset-mac.def                                  *}
\Msg{*     ctex-fontset-macnew.def                               *}
\Msg{*     ctex-fontset-macold.def                               *}
\Msg{*     ctex-fontset-ubuntu.def                               *}
\Msg{*     ctex-fontset-windows.def                              *}
\Msg{*     ctexspa.def                                           *}
\Msg{*     ctex-spa-make.tex                                     *}
\Msg{*     ctex-spa-macro.tex                                    *}
\Msg{*     ctex-zhmap-adobe.tex                                  *}
\Msg{*     ctex-zhmap-fandol.tex                                 *}
\Msg{*     ctex-zhmap-founder.tex                                *}
\Msg{*     ctex-zhmap-mac.tex                                    *}
\Msg{*     ctex-zhmap-ubuntu.tex                                 *}
\Msg{*     ctex-zhmap-windows.tex                                *}
\Msg{*     translator-theorem-dictionary-ChineseGBK.dict         *}
\Msg{*     translator-theorem-dictionary-ChineseUTF8.dict        *}
\Msg{*                                                           *}
\Msg{* To produce the documentation run the file ctex.dtx        *}
\Msg{* through XeLaTeX.                                          *}
\Msg{*                                                           *}
\Msg{* Happy TeXing!                                             *}
\Msg{*                                                           *}
\Msg{*************************************************************}

\endbatchfile
%&lt;/install&gt;
%&lt;*internal&gt;
\fi
%&lt;/internal&gt;
%&lt;*!(driver|readme|install|zhmap|spa|docstrip)&gt;
%&lt;*!(fd|ctexspa|dict|backend)&gt;
%&lt;class|style|ctexcap|ctexhook|ctexpatch&gt;\NeedsTeXFormat{LaTeX2e}
%&lt;class&gt;\input{ctexbackend.cfg}
%&lt;class|style|ctexcap|ctexhook|ctexpatch&gt;\RequirePackage{expl3}
%&lt;+!driver&gt;\GetIdInfo$Id: ctex.dtx 13a2256 2022-07-14 18:54:09 +0800 Qing Lee &lt;sobenlee@gmail.com&gt; $
%&lt;ctex&gt;  {Chinese adapter in LaTeX (CTEX)}
%&lt;ctex&gt;\ProvidesExplPackage{\ExplFileName}
%&lt;ctexsize&gt;  {Chinese font size definition (CTEX)}
%&lt;ctexsize&gt;\ProvidesExplPackage{ctexsize}
%&lt;ctexheading&gt;  {Heading style modification (CTEX)}
%&lt;ctexheading&gt;\ProvidesExplPackage{ctexheading}
%&lt;class&amp;article&gt;  {Chinese adapter for class article (CTEX)}
%&lt;class&amp;article&gt;\ProvidesExplClass{ctexart}
%&lt;class&amp;book&gt;  {Chinese adapter for class book (CTEX)}
%&lt;class&amp;book&gt;\ProvidesExplClass{ctexbook}
%&lt;class&amp;report&gt;  {Chinese adapter for class report (CTEX)}
%&lt;class&amp;report&gt;\ProvidesExplClass{ctexrep}
%&lt;class&amp;beamer&gt;  {Chinese adapter for class beamer (CTEX)}
%&lt;class&amp;beamer&gt;\ProvidesExplClass{ctexbeamer}
%&lt;ctexcap&gt;  {Chinese adapter in LaTeX (CTEX)}
%&lt;ctexcap&gt;\ProvidesExplPackage{ctexcap}
%&lt;ctexhook&gt;  {Document and package hooks (CTEX)}
%&lt;ctexhook&gt;\ProvidesExplPackage{ctexhook}
%&lt;ctexpatch&gt;  {Patching commands (CTEX)}
%&lt;ctexpatch&gt;\ProvidesExplPackage{ctexpatch}
%&lt;c5size&gt;  {c5size option (CTEX)}
%&lt;c5size&gt;\ProvidesExplFile{ctex-c5size.clo}
%&lt;cs4size&gt;  {cs4size option (CTEX)}
%&lt;cs4size&gt;\ProvidesExplFile{ctex-cs4size.clo}
%&lt;heading&amp;article&gt;  {Heading modification for article (CTEX)}
%&lt;heading&amp;article&gt;\ProvidesExplFile{ctex-article.def}
%&lt;heading&amp;book&gt;  {Heading modification for book (CTEX)}
%&lt;heading&amp;book&gt;\ProvidesExplFile{ctex-book.def}
%&lt;heading&amp;report&gt;  {Heading modification for report (CTEX)}
%&lt;heading&amp;report&gt;\ProvidesExplFile{ctex-report.def}
%&lt;heading&amp;beamer&gt;  {Heading modification for beamer (CTEX)}
%&lt;heading&amp;beamer&gt;\ProvidesExplFile{ctex-beamer.def}
%&lt;scheme&amp;plain&amp;generic&gt;  {Plain scheme for generic (CTEX)}
%&lt;scheme&amp;plain&amp;generic&gt;\ProvidesExplFile{ctex-scheme-plain.def}
%&lt;scheme&amp;plain&amp;article&gt;  {Plain scheme for article (CTEX)}
%&lt;scheme&amp;plain&amp;article&gt;\ProvidesExplFile{ctex-scheme-plain-article.def}
%&lt;scheme&amp;plain&amp;book&gt;  {Plain scheme for book (CTEX)}
%&lt;scheme&amp;plain&amp;book&gt;\ProvidesExplFile{ctex-scheme-plain-book.def}
%&lt;scheme&amp;plain&amp;report&gt;  {Plain scheme for report (CTEX)}
%&lt;scheme&amp;plain&amp;report&gt;\ProvidesExplFile{ctex-scheme-plain-report.def}
%&lt;scheme&amp;plain&amp;beamer&gt;  {Plain scheme for beamer (CTEX)}
%&lt;scheme&amp;plain&amp;beamer&gt;\ProvidesExplFile{ctex-scheme-plain-beamer.def}
%&lt;scheme&amp;chinese&amp;generic&gt;  {Chinese scheme for generic (CTEX)}
%&lt;scheme&amp;chinese&amp;generic&gt;\ProvidesExplFile{ctex-scheme-chinese.def}
%&lt;scheme&amp;chinese&amp;article&gt;  {Chinese scheme for article (CTEX)}
%&lt;scheme&amp;chinese&amp;article&gt;\ProvidesExplFile{ctex-scheme-chinese-article.def}
%&lt;scheme&amp;chinese&amp;book&gt;  {Chinese scheme for book (CTEX)}
%&lt;scheme&amp;chinese&amp;book&gt;\ProvidesExplFile{ctex-scheme-chinese-book.def}
%&lt;scheme&amp;chinese&amp;report&gt;  {Chinese scheme for report (CTEX)}
%&lt;scheme&amp;chinese&amp;report&gt;\ProvidesExplFile{ctex-scheme-chinese-report.def}
%&lt;scheme&amp;chinese&amp;beamer&gt;  {Chinese scheme for beamer (CTEX)}
%&lt;scheme&amp;chinese&amp;beamer&gt;\ProvidesExplFile{ctex-scheme-chinese-beamer.def}
%&lt;name&amp;GBK&gt;  {Caption with encoding GBK (CTEX)}
%&lt;name&amp;GBK&gt;\ProvidesExplFile{ctex-name-gbk.cfg}
%&lt;name&amp;UTF8&gt;  {Caption with encoding UTF-8 (CTEX)}
%&lt;name&amp;UTF8&gt;\ProvidesExplFile{ctex-name-utf8.cfg}
%&lt;config&gt;  {Configuration file (CTEX)}
%&lt;config&gt;\ProvidesExplFile{\ExplFileName.cfg}
%&lt;ctexopts&gt;  {Option configuration file (CTEX)}
%&lt;ctexopts&gt;\ProvidesExplFile{ctexopts.cfg}
%&lt;pdftex&gt;  {(pdf)LaTeX adapter (CTEX)}
%&lt;pdftex&gt;\ProvidesExplFile{ctex-engine-pdftex.def}
%&lt;xetex&gt;  {XeLaTeX adapter (CTEX)}
%&lt;xetex&gt;\ProvidesExplFile{ctex-engine-xetex.def}
%&lt;luatex&gt;  {LuaLaTeX adapter (CTEX)}
%&lt;luatex&gt;\ProvidesExplFile{ctex-engine-luatex.def}
%&lt;aptex&gt;  {Asian pTeX adapter (CTEX)}
%&lt;aptex&gt;\ProvidesExplFile{ctex-engine-aptex.def}
%&lt;uptex&gt;  {upTeX adapter (CTEX)}
%&lt;uptex&gt;\ProvidesExplFile{ctex-engine-uptex.def}
%&lt;windows&gt;  {Windows fonts definition (CTEX)}
%&lt;windows&gt;\ProvidesExplFile{ctex-fontset-windows.def}
%&lt;adobe&gt;  {Adobe fonts definition (CTEX)}
%&lt;adobe&gt;\ProvidesExplFile{ctex-fontset-adobe.def}
%&lt;fandol&gt;  {Fandol fonts definition (CTEX)}
%&lt;fandol&gt;\ProvidesExplFile{ctex-fontset-fandol.def}
%&lt;mac&gt;  {macOS fonts definition (CTEX)}
%&lt;mac&gt;\ProvidesExplFile{ctex-fontset-mac.def}
%&lt;macnew&gt;  {macOS fonts definition for El Capitan or later version (CTEX)}
%&lt;macnew&gt;\ProvidesExplFile{ctex-fontset-macnew.def}
%&lt;macold&gt;  {macOS fonts definition for Yosemite or earlier version (CTEX)}
%&lt;macold&gt;\ProvidesExplFile{ctex-fontset-macold.def}
%&lt;founder&gt;  {Founder fonts definition (CTEX)}
%&lt;founder&gt;\ProvidesExplFile{ctex-fontset-founder.def}
%&lt;ubuntu&gt;  {Ubuntu fonts definition (CTEX)}
%&lt;ubuntu&gt;\ProvidesExplFile{ctex-fontset-ubuntu.def}
%&lt;!driver&gt;  {\ExplFileDate}{2.5.10}{\ExplFileDescription}
%&lt;/!(fd|ctexspa|dict|backend)&gt;
%&lt;c19&amp;rm&gt;\ProvidesFile{c19rm.fd}%
%&lt;c19&amp;sf&gt;\ProvidesFile{c19sf.fd}%
%&lt;c19&amp;tt&gt;\ProvidesFile{c19tt.fd}%
%&lt;c70&amp;rm&gt;\ProvidesFile{c70rm.fd}%
%&lt;c70&amp;sf&gt;\ProvidesFile{c70sf.fd}%
%&lt;c70&amp;tt&gt;\ProvidesFile{c70tt.fd}%
%&lt;jy2&amp;rm&gt;\ProvidesFile{jy2zhrm.fd}%
%&lt;jy2&amp;sf&gt;\ProvidesFile{jy2zhsf.fd}%
%&lt;jy2&amp;tt&gt;\ProvidesFile{jy2zhtt.fd}%
%&lt;jt2&amp;rm&gt;\ProvidesFile{jt2zhrm.fd}%
%&lt;jt2&amp;sf&gt;\ProvidesFile{jt2zhsf.fd}%
%&lt;jt2&amp;tt&gt;\ProvidesFile{jt2zhtt.fd}%
%&lt;ctexspa&gt;\ProvidesFile{ctexspa.def}%
%&lt;backend&gt;\ProvidesFile{ctexbackend.cfg}%
%&lt;dict&amp;theorem&amp;GBK&gt;\ProvidesDictionary{translator-theorem-dictionary}{ChineseGBK}%
%&lt;dict&amp;theorem&amp;UTF8&gt;\ProvidesDictionary{translator-theorem-dictionary}{ChineseUTF8}%
%&lt;fd&gt;  [2022/07/14 v2.5.10 Chinese font definition (CTEX)]
%&lt;ctexspa&gt;  [2022/07/14 v2.5.10 Space info for CJKpunct (CTEX)]
%&lt;backend&gt;  [2022/07/14 v2.5.10 Backend configuration file (CTEX)]
%&lt;dict&amp;theorem&gt;  [2022/07/14 v2.5.10 Chinese translation for theorem name (CTEX)]
%&lt;/!(driver|readme|install|zhmap|spa|docstrip)&gt;
%&lt;*driver&gt;
\documentclass{ctxdoc}
\begin{document}
  \DocInput{\jobname.dtx}
  \IndexLayout
  \PrintChanges
  \PrintIndex
\end{document}
%&lt;/driver&gt;
%
% \fi
%
% \changes{v2.0}{2014/03/06}{应用 \LaTeXiii{} 重新整理代码。}
% \changes{v2.0}{2014/03/12}{删除 \file{c19gbsn.fd} 和 \file{c19gkai.fd}。}
% \changes{v2.1}{2015/05/18}{将章节标题设置功能提取到可以独立使用的宏包
%   \pkg{ctexheading} 中。}
% \changes{v2.2}{2015/06/24}{不再依赖 \pkg{etoolbox} 宏包。}
% \changes{v2.4}{2015/02/19}{加强 \pkg{beamer} 宏包支持。}
% \changes{v2.4.12}{2018/01/13}{同步 \LaTeXiii{} 2017/12/16。}
% \changes{v2.4.15}{2019/03/23}{同步 \LaTeXiii{} 2019/03/05。}
% \changes{v2.5.1}{2020/05/02}{\pkg{zhconv} 更名为 \pkg{ctex-zhconv}。}
%
% \CheckSum{6630}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&amp;
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \&lt;
%   Equals        \=     Greater than  \&gt;     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
% \GetFileId{ctex.sty}
%
% \title{\bfseries \CTeX{} 宏集手册}
% \author{\href{http://www.ctex.org}{CTEX.ORG}}
% \date{\filedate\qquad\fileversion\thanks{\ctexkitrev{\ExplFileVersion}.}}
% \maketitle
%
% \begin{abstract}
% \CTeX{} 宏集是面向中文排版的通用 \LaTeX{} 排版框架，为中文 \LaTeX{} 文档
% 提供了汉字输出支持、标点压缩、字体字号命令、标题文字汉化、中文版式调整、数字
% 日期转换等支持功能，可适应论文、报告、书籍、幻灯片等不同类型的中文文档。
%
% \CTeX{} 宏集支持 \LaTeX、\pdfLaTeX、\XeLaTeX、\LuaLaTeX、\upLaTeX{} 等多种不同
% 的编译方式，并为它们提供了统一的界面。主要功能由宏包 \pkg{ctex} 以及中文文档类
% \cls{ctexart}、\cls{ctexrep}、\cls{ctexbook} 和 \cls{ctexbeamer} 实现。
% \end{abstract}
%
% \tableofcontents
%
% \bigskip
% \setlength{\parskip}{0.8ex}
%
% \begin{documentation}
%
% \section{介绍}
%
% \subsection*{历史}
%
% \CTeX{} 宏集的源头有两个：一是王磊编写的 \cls{cjkbook} 文档类，二是吴凌云编写的
% \file{GB.cap}。
% 这些工作没有经过认真系统的设计，也没有用户文档，不利于维护和改进。
%
% 2003 年，吴凌云使用 \pkg{doc} 和 \pkg{DocStrip} 重构了整个工程，并增加了许多新的功能，
% 称为 \pkg{ctex} 宏包。2007 年，oseen 和王越在 \pkg{ctex} 宏包的基础上，
% 增加了对 UTF-8 编码的支持，开发出了 \pkg{ctexutf8} 宏包。
%
% 2009 年 5 月，我们在 Google Code 建立了 ctex-kit 项目^^A
% \footnote{\nolinkurl{http://code.google.com/p/ctex-kit/}，该链接现已失效。}，
% 对 \pkg{ctex} 宏包及相关脚本进行了整合，并加入了对 \XeTeX{} 引擎的支持。
% 在开发新版本时，考虑到合作开发和调试的方便，我们放弃了 \pkg{doc} 和 \pkg{DocStrip}，
% 采取了直接编写宏包代码的方式。
%
% 2014 年 3 月，为了适应 \LaTeX{} 的最新发展，特别是 \LaTeXiii{} 的逐渐成熟，李清用
% \LaTeXiii{} 重构了整个宏包的代码，并重新使用 \pkg{doc} 和 \pkg{DocStrip} 工具进行代码
% 的管理，升级版本号为 2.0，并改称 \CTeX{} 宏集。
%
% 2015 年 3 月，由于 Google Code 即将停止服务，ctex-kit 项目迁移至
% \href{https://github.com/CTeX-org/ctex-kit}{GitHub}^^A
% \footnote{\url{https://github.com/CTeX-org/ctex-kit}}。
%
% 最初，Knuth 在设计开发 \TeX{} 的时候没有考虑到多国文字支持，特别是对多字节的中日韩
% 表意文字的支持。这使得 \TeX{} 以至后来的 \LaTeX{} 对中文的支持一直不是很好。即使在
% \pkg{CJK} 宏包解决了中文字符处理的问题以后，中文用户使用 \LaTeX{} 仍然要面对许
% 多困难。
% 这些困难里，以章节标题的中文化为最。由于中文和西文书写习惯的差异，用户很难使用标准
% 文档类中的代码结构来表达中文标题。于是，用户不得不对标准文档类做较大的修改。
% 除此之外，日期格式、首行缩进、中文字号和字距等细节问题，也需要精细的调校。
% 我们设计 \CTeX{} 宏集的目的之一就是解决这些 \LaTeX{} 文档的汉化难题。
%
% 另一方面，随着 \TeX{} 引擎和 \LaTeX{} 宏包的不断发展，\LaTeX{} 的中文支持方式从早期的
% 专用系统（如 \pkg{CCT}）发展为适用于不同引擎的多种方式^^A
% \footnote{比如：\pdfTeX{} 引擎下的 \pkg{CJK}、\pkg{zhmCJK}宏包，
% \XeTeX{} 引擎下的 \pkg{xeCJK} 宏包和 \LuaTeX{} 引擎下的 \pkg{LuaTeX-ja} 宏包。}。
% 这些方式的适用情况和使用方式有不少细节上的差异，同时操作系统的不同、语言环境的不同等
% 客观情况又进一步带来了更多的细节差异。我们设计 \CTeX{} 宏集的另一个主要目的就是
% 尽可能消除这些差异带来的影响，使用户能够以一个统一的接口来使用不同的中文支持方式，
% 使得同一份文档能够在不同环境下交换使用。
%
% \CTeX{} 宏集的许多实现细节离不开热心朋友们在 \nolinkurl{bbs.ctex.org} 论坛^^A
% \footnote{2018 年，\CTeX{} 论坛因故无限期关闭，此链接现已失效。}^^A
% 上的讨论，在此对参与讨论的朋友们表示感谢。
%
% \subsection*{关于宏集名字的说明}
%
% \CTeX{} 之名是英文单词 China（中国）或 Chinese（中文）的首字母“C”与 “\TeX{}”
% 结合而成的。在纯文本环境下，该名字应写作“CTeX”。
%
% \CTeX{} 宏集是由 \href{https://github.com/CTeX-org}{\CTeX{} 社区}发起并维护的
% \LaTeX{} \emph{宏包和文档类的集合}。
% 社区另有发布名为 \href{http://www.ctex.org/CTeX}{\CTeX{} 套装}^^A
% 的 \TeX{} 发行版，与本文档所述的 \CTeX{} 宏集并非是同一事物。
%
% \pkg{ctex} 则是本宏集中的 \pkg{ctex.sty} 的名字。这一完全小写的名称，在过去
% 也被用来指代整个 \CTeX{} 宏集，不过现在则特指 \pkg{ctex.sty} 这一宏包。
% 在不引起歧义的情况下，它也可以沿用过去的习惯，代指整个宏集。
%
% \section{简明教程}
%
% \subsection{\CTeX{} 宏集的组成}
%
% 为了适应用户不同的需求，我们将 \CTeX{} 宏集的主要功能设计安排在四个中文文档类和
% 三个宏包当中，具体的组成见表~\ref{tab:ctex}。
%
% \begin{table}[htbp]
% \centering
% \caption{\CTeX{} 宏集的组成}\label{tab:ctex}
% \begin{tabularx}{\linewidth}{llX}
% \toprule
%   类别   &amp; 文件 &amp; 说明 \\
% \midrule
%   文档类 &amp; \file{ctexart.cls}    &amp; 标准文档类 \cls{article} 的汉化版本，
%                                    一般适用于短篇幅的文章 \\
%          &amp; \file{ctexrep.cls}    &amp; 标准文档类 \cls{report} 的汉化版本，
%                                    一般适用于中篇幅的报告 \\
%          &amp; \file{ctexbook.cls}   &amp; 标准文档类 \cls{book} 的汉化版本，
%                                    一般适用于长篇幅的书籍 \\
%          &amp; \file{ctexbeamer.cls} &amp; 文档类 \cls{beamer} 的汉化版本，
%                                    适用于幻灯片演示 \\
% \midrule
%   宏包   &amp; \file{ctex.sty}        &amp; 提供全部功能，但\emph{默认不开启章节标题设置功能}，
%                                     需要使用 \opt{heading} 选项来开启 \\
%          &amp; \file{ctexsize.sty}    &amp; 定义和调整中文字号，可以在 \pkg{ctex} 宏包
%                                     或 \CTeX{} 中文文档类之外单独调用 \\
%          &amp; \file{ctexheading.sty} &amp; 提供章节标题设置功能（见 \ref{sec:secstyle}
%                                     节），可以在 \pkg{ctex} 宏包或 \CTeX{} 中文
%                                     文档类之外单独调用 \\
% \bottomrule
% \end{tabularx}
% \end{table}
%
% \subsection{\CTeX{} 宏集的安装和更新}
% \label{subsec:easy-ins}
% 最常见的 \TeX{} 发行版（\TeXLive{} 和 \MiKTeX{}）已收录 \CTeX{} 宏集及其依赖的宏包和宏集。
% \footnote{\pkg{zhmCJK} 宏包是个例外。当用户显式指定选项 \opt{zhmap = zhmCJK} 时，^^A
% \CTeX{} 宏集依赖它。由于，它没有被 \TeXLive{} 和 \MiKTeX{} 收录，用户可能需要遵照其说明文档
% 自行安装。}如果本地安装 \TeXLive{} 或 \MiKTeX{} 不是完整版本，则可能需要通过这
% 两个发行版提供的\emph{包管理器}来安装宏包。
%
% \TeXLive{} 的包管理器是 tlmgr（\TeXLive{} Manager）。用户可以在系统命令行中^^A
% \footnote{Windows 系统的命令行是 CMD 命令提示符，你可以使用 Win + R 组合键
% 打开“运行”对话框，然后输入 cmd 确认打开命令提示符窗口。}执行
% \begin{frameverb}
%   tlmgr gui
% \end{frameverb}
% 启动管理器的图形界面（Windows 用户也可以通过开始菜单的 TeX Live 20XX（年份）
% \ding{212} TeX Live Manager 打开）。连接上远程仓库之后，搜索 |ctex| 即可安装。
% tlmgr 的图形界面使用 Perl 编写，在实践中发现容易造成系统假死。遇到这种问题的用户，
% 也可以直接在系统命令行执行
% \begin{frameverb}
%   tlmgr install ctex
% \end{frameverb}
% 来安装 \CTeX{} 宏集^^A
% \footnote{*nix 用户可能需要超级用户权限（sudo）才能正确安装宏集。}。
%
% \MiKTeX{} 通常会在缺失宏包时自动完成安装。如需手动安装，可以使用其管理维护
% 工具 \MiKTeX{} Console。用户可以打开管理器，连接上远程仓库之后，在“Package”
% 选项卡中搜索“ctex”并安装即可。
% 也可以使用 mpm（\MiKTeX{} Package Manager），在命令行执行
% \begin{frameverb}
%   mpm --admin --install=ctex
% \end{frameverb}
% 来安装 \CTeX{} 宏集。
%
% 若希望了解 \CTeX{} 宏集具体的依赖情况或手工安装宏集的方法，
% 请参阅第 \ref{sec:dep-ins}~节。
%
% 当我们将宏集的新版本发布于 CTAN，且为发行版的远程仓库更新后，用户就可以在本地
% 通过包管理器获取新版本。
%
% 对于 \TeXLive{}，可以在 tlmgr 的图形界面点击“更新全部已安装的”按钮或者在
% 命令行执行
% \begin{frameverb}
%   tlmgr update --all
% \end{frameverb}
% 来完整更新已安装的宏包。
%
% 对于 \MiKTeX{}，在 \MiKTeX{} Console 中找到“Updates”选项卡，检查更新后即可
% 选择升级宏包。也可以使用 mpm，在命令行执行
% \begin{frameverb}
%   mpm --admin --update
% \end{frameverb}
% 来进行更新。
%
% \subsection{使用 \CTeX{} 文档类}
%
% \emph{如果用户需要在三个标准文档类或 \cls{beamer} 的基础上添加中文及版式的支持，
% 我们建议用户使用 \CTeX{} 宏集提供的四个中文文档类。}
%
% \CTeX{} 宏集提供了四个中文文档类：\cls{ctexart}、\cls{ctexrep}、\cls{ctexbook} 和
% \cls{ctexbeamer}，分别对应 \LaTeX{} 的标准文档类 \cls{article}、\cls{report}、
% \cls{book} 和 \cls{beamer}。使用它们的时候，需要将涉及到的所有源文件使用 UTF-8
% 编码保存\footnote{使用 (pdf)\LaTeX{} 时也能够使用 GBK 编码，但不推荐。（见
% \ref{subs:encoding}~节）}。
%
% \begin{ctexexam}
%   \documentclass{ctexart}
%   \begin{document}
%   中文文档类测试。你需要将所有源文件保存为 UTF-8 编码。
%
%   你可以使用 XeLaTeX、LuaLaTeX 或 upLaTeX 编译，也可以使用 (pdf)LaTeX 编译。
%   推荐使用 XeLaTeX 或 LuaLaTeX 编译。对高级用户，我们也推荐使用 upLaTeX 编译。
%   \end{document}
% \end{ctexexam}
%
% 以下是使用 \cls{ctexbeamer} 文档类编写中文演示文稿的一个示例。
% \begin{ctexexam}
%   \documentclass{ctexbeamer}
%   \begin{document}
%   \begin{frame}{中文演示文档}
%   \begin{itemize}
%     \item 你需要将所有源文件保存为 UTF-8 编码
%     \item 你可以使用 XeLaTeX、LuaLaTeX 或 upLaTeX 编译
%     \item 也可以使用 (pdf)LaTeX 编译
%     \item 推荐使用 XeLaTeX 或 LuaLaTeX 编译
%     \item 对高级用户，我们也推荐使用 upLaTeX 编译
%   \end{itemize}
%   \end{frame}
%   \end{document}
% \end{ctexexam}
%
% \subsection{使用 \pkg{ctex} 宏包}
%
% \emph{用户在使用非标准文档类及 \cls{beamer} 时，如果需要添加中文及版式的支持，
% 则可以使用 \pkg{ctex} 宏包。}
%
% 对于建立在 \LaTeX{} 标准文档类之上开发的文档类，在使用 \pkg{ctex} 宏包时
% 加上 \opt{heading} 选项，可以将章节标题设置为中文风格。
% \begin{ctexexam}
%   \documentclass{ltxdoc}
%   \usepackage[heading = true]{ctex}
%   \begin{document}
%   \section{简介}
%   章节标题中文化的 \LaTeX{} 手册。
%   \end{document}
% \end{ctexexam}
%
% \section{宏包选项与 \tn{ctexset} 命令}
% \label{sec:options}
%
% \CTeX{} 宏集已经尽可能就中文的行文和版式习惯做了调整和配置，通常而言，这些配置
% 已经够用。因此，除非必要，我们不建议普通用户修改这些默认配置。如果你认为 \CTeX{} 宏集
% 的默认配置还可以完善，可以在项目主页上^^A
% \href{https://github.com/CTeX-org/ctex-kit/issues}{提交 issue}，
% 向我们反映，我们会酌情在后续版本中予以改进。
%
% 不过，\CTeX{} 宏集也提供了一系列选项。用户可以使用这些选项来控制 \CTeX{} 宏集的行为。
% 按形式分类，这些选项有的以传统的方式提供，有的以 \meta{key}|=|\meta{value} 的形式提供。
% 按指定位置分类，这些选项又可以分为以下三类：
% \begin{itemize}
% \item 名字后带有 \rexptarget\rexpstar{} 号的选项，只能作为宏包/文档类选项，需要
%   在引入宏包/文档类的时候指定；
% \item 名字后带有 \exptarget\expstar{} 号的选项，只能通过 \CTeX{} 宏集提供的
%   用户接口 \tn{ctexset} 来设定；
% \item 名字后不带有特殊符号的选项，既可以作为宏包/文档类选项，也可以通过
%   \tn{ctexset} 来设定。
% \end{itemize}
% 后续文档将在使用说明中对某些特殊的选项加以说明。
%
% \begin{function}[added=2014-03-18]{\ctexset}
%   \begin{syntax}
%     \tn{ctexset} \Arg{键值列表}
%   \end{syntax}
% 是 \CTeX{} 宏集的通用控制命令，用来在宏包载入后控制宏包的各项功能。
% \tn{ctexset} 的参数是一个键值列表，以通用的接口完成各项设置。
% \end{function}
%
% \tn{ctexset} 的参数是一组由逗号分隔的选项列表，列表中的选项通常是一个
% \meta{key}|=|\meta{value} 格式的定义。例如设置摘要与参考文献标题名称
% （\ref{subs:capname}~节）就可以使用：
% \begin{ctexexam}[labelref=exam:capname]
%   \ctexset{
%     abstractname = {本文概要},
%     bibname      = {文\quad 献}
%   }
% \end{ctexexam}
%
% \tn{ctexset} 采用 \LaTeXiii{} 风格的键值设置，支持不同类型的选项与层次化的选
% 项设置，相关示例见 \ref{sec:secstyle}~节。
%
% \section{编译方式、编码与中文字库}
% \label{sec:chinese}
%
% \subsection{编译方式}
% \label{subs:compile}
%
% \CTeX{} 宏集会根据用户使用的编译方式\footnote{\LaTeX、\pdfLaTeX、\XeLaTeX、
% \LuaLaTeX{} 及 \upLaTeX。}，在底层选择不同的中文支持方式（见
% 表~\ref{tab:chinese-support}）。
%
% \begin{table}[htbp]
% \centering
% \begin{threeparttable}
% \caption{\CTeX{} 宏集的中文支持方式}
% \label{tab:chinese-support}
% \begin{tabular}{*6c}
%   \toprule
%   编译方式 &amp; (pdf)\LaTeX &amp; \XeLaTeX &amp; \LuaLaTeX &amp; \upLaTeX\tnote{*} \\
%   \midrule
%   支持宏包 &amp; \pkg{CJK} &amp; \pkg{xeCJK} &amp; \pkg{LuaTeX-ja} &amp; 原生 \\
%   \bottomrule
% \end{tabular}
% \begin{tablenotes}
% \item[*] p\LaTeX-ng（或称 \ApLaTeX）与 \upLaTeX{} 兼容。使用 p\LaTeX-ng 编译
% 时，\pkg{ctex} 采用与 \upLaTeX{} 相同的设置。
% \end{tablenotes}
% \end{threeparttable}
% \end{table}
%
% 不同的编译方式和中文支持方式会在一定程度上影响 \CTeX{} 宏集的行为，比如宏包对
% 文档编码、字体选择、空格、标点等的处理。具体细节将在本文档后续内容中进行阐述。
%
% \subsection{中文编码}
% \label{subs:encoding}
%
% \begin{function}[rEXP,updated=2019-11-10]{GBK, UTF8}
%   指明编写文档时使用的编码。\CTeX{} 宏集无法检测文档源文件的实际编码格式，因此需要
%   用户通过选项声明。如果没有显式指定，则默认采用 UTF-8 编码。
%
%   使用 \XeLaTeX{}、\LuaLaTeX{} 或 \upLaTeX{} 编译时，\CTeX{} 宏集强制使用
%   UTF-8 编码，此时 \opt{GBK} 选项无效；使用 (pdf)\LaTeX{} 编译时，
%   \CTeX{} 宏集默认使用 UTF-8 编码，但用户也可以显式声明 \opt{GBK} 选项，
%   使 \CTeX{} 宏集按 GBK 编码处理文档。
%
%   用户需要\emph{保证编译方式、源文件编码、宏包编码选项三者一致}。
%
%   \emph{我们建议编写新文档时始终使用 UTF-8 编码，而仅把 GBK 编码留给
%   历史遗留文档。}
% \end{function}
%
% \subsection{中文字库}
% \label{subs:options-CJK-font}
%
% 以往，为 \LaTeX{} 文档配置中文支持是一件相当繁琐的事情。默认情况下，
% \CTeX{} 宏集能自动检测用户使用的编译方式（参见 \ref{subs:compile}~节）和
% 操作系统\footnote{\CTeX{} 宏集现在能够识别 macOS 及 Windows 系统，
% 并将其他系统统一归为 Linux。}，选择合适的底层支持和字库，从而简化配置过程。
% 自动配置的情况参见表~\ref{tab:default-font-select}。
%
% \begin{table}[htbp]
% \centering
% \begin{threeparttable}
% \caption{\CTeX{} 宏集自动配置字体策略}
% \label{tab:default-font-select}
% \begin{tabular}{*{5}{c}}
%   \toprule
%              &amp; macOS Old\tnote{1}
%              &amp; macOS New\tnote{2}
%              &amp; Windows\tnote{3}
%              &amp; 其他 \\
%   \midrule
%   \XeLaTeX   &amp; \makecell{\pkg{xeCJK}\\华文字库}
%              &amp; \makecell{\pkg{xeCJK}\\华文字库 + 苹方}
%              &amp; \makecell{\pkg{xeCJK}\\中易字库 + 微软雅黑}
%              &amp; \makecell{\pkg{xeCJK}\\Fandol 字库\tnote{4}} \\
%   \cmidrule(lr){1-5}
%   \LuaLaTeX\tnote{5}
%              &amp; \makecell{\pkg{LuaTeX-ja}\\华文字库}
%              &amp; \makecell{\pkg{LuaTeX-ja}\\华文字库 + 苹方}
%              &amp; \makecell{\pkg{LuaTeX-ja}\\中易字库 + 微软雅黑}
%              &amp; \makecell{\pkg{LuaTeX-ja}\\Fandol 字库} \\
%   \cmidrule(lr){1-5}
%   \pdfLaTeX
%              &amp; 不可用
%              &amp; 不可用
%              &amp; \makecell{\pkg{CJK} + \pkg{zhmetrics}\\中易字库 + 微软雅黑\tnote{6}}
%              &amp; 不可用 \\
%   \cmidrule(lr){1-5}
%   \makecell{\LaTeX{} + \\\dvipdfmx}
%              &amp; 不可用
%              &amp; \makecell{\pkg{CJK} + \pkg{zhmetrics}\\华文字库 + 苹方}
%              &amp; \makecell{\pkg{CJK} + \pkg{zhmetrics}\\中易字库 + 微软雅黑\tnote{6}}
%              &amp; \makecell{\pkg{CJK} + \pkg{zhmetrics}\\Fandol 字库} \\
%   \cmidrule(lr){1-5}
%   \makecell{\upLaTeX{} + \\\dvipdfmx}
%              &amp; 不可用
%              &amp; \makecell{\pkg{zhmetrics-uptex}\\华文字库 + 苹方}
%              &amp; \makecell{\pkg{zhmetrics-uptex}\\中易字库 + 微软雅黑}
%              &amp; \makecell{\pkg{zhmetrics-uptex}\\Fandol 字库} \\
%   \bottomrule
% \end{tabular}
% \begin{tablenotes}
%   \item [1] Yosemite (10.10) 及以前的 macOS 系统。
%   \item [2] El Capitan (10.11) 及以后的 macOS 系统。
%   \item [3] 仅支持 Windows Vista 及以后的 Windows 操作系统。
%   \item [4] 由马起园、苏杰、黄晨成等人开发的开源中文字体，
%     参见：\url{https://www.ctan.org/pkg/fandol}。
%   \item [5] \LuaLaTeX{} 编译时使用 \pkg{LuaTeX-ja} 宏包。对此，
%     第 \ref{sec:lualatex-chinese}~节有特别说明。
%   \item [6] 微软雅黑字体并不总是有效，这和选项 \opt{zhmap} 的取值有关。
% \end{tablenotes}
% \end{threeparttable}
% \end{table}
%
% 通常，由 \CTeX{} 宏集进行的自动配置已经足够使用，无需用户手工干预；但
% 是 \CTeX{} 仍然提供了一系列选项，供在 \CTeX{} 的自动选择机制因为
% 意外情况失效，或者在用户有特殊需求的情况下使用。\emph{除非必要，用户不
% 应使用这些选项。}
%
% \begin{function}[rEXP,updated=2014-03-08]{zhmap}
%   \begin{syntax}
%     zhmap = &lt;\TTF|zhmCJK&gt;
%   \end{syntax}
%   指定字体映射机制。本选项只在使用 (pdf)\LaTeX{} 编译时有意义。
% \end{function}
% \begin{optdesc}
%   \item[true] 这是该选项的默认值。^^A
%   \footnote{对于以键值对形式提供的选项，文档以\textbf{粗体}来表示其默认值。^^A
%   下同，不再额外解释。}使用 \pkg{zhmetrics} 宏包，将 CJK 字库通过 \tn{special}
%   命令映射到 \file{.ttf} 文件。
%
%   \item[false] 使用传统的 CJK 字库（Type 1）^^A
%   \footnote{使用 (pdf)\LaTeX{} 编译时，如果需要使用自定义的字体映射文件（比如需要
%     使用 \LaTeX{} + Dvips 编译），或者希望使用 Type1 字库，请禁用本选项。为此，你
%     可能需要安装 CJK 字体。参考 \pkg{zhmetrics} 宏包提供的脚本
%     \href{https://github.com/CTeX-org/ctex-kit/blob/master/zhmetrics/CTeXFonts.lua}
%     {\file{CTeXFonts.lua}}。}。
%
%   \item[zhmCJK] 载入 \pkg{zhmCJK} 宏包^^A
%   \footnote{\pkg{zhmCJK} 宏包基于 \pkg{zhmetrics} 和 \pkg{CJK} 宏包，提供与
%   \pkg{xeCJK} 宏包类似的用户接口。}^^A
%   ，由 \pkg{zhmCJK} 宏包提供从 CJK 字库到 \file{.ttf} 的映射。
% \end{optdesc}
%
% \begin{function}[added=2014-03-08]{fontset}
%   \begin{syntax}
%     fontset = &lt;adobe|fandol|founder|mac|macnew|macold|ubuntu|windows|none|...&gt;
%   \end{syntax}
%   指定 \CTeX{} 宏集加载的字库。
%
%   如果没有指定 \opt{fontset} 的值，\CTeX{} 宏集将自动检测用户使用的操作系统，配置
%   相应的字体（参见表~\ref{tab:default-font-select}）。
% \end{function}
%
% \CTeX{} 预定义了以下六种中文字库。
%
% \begin{optdesc}
%   \item[adobe] 使用 Adobe 公司的四款中文字体，\emph{不支持 \pdfLaTeX}。
%   \item[fandol] 使用 Fandol 中文字体，\emph{不支持 \pdfLaTeX}。
%   \item[founder] 使用方正公司的中文字体。
%   \item[mac] 使用 macOS 系统下的字体，\emph{不支持 \pdfLaTeX}，根据版本分为
%     |macnew| 和 |macold| 两种。
%   \item[macnew] 使用 El Capitan 或之后的多字重华文字体和苹方字体。
%   \item[macold] 使用 Yosemite 或之前的华文字体。
%   \item[ubuntu] 使用 Ubuntu 系统下的思源宋体、思源黑体和 \TeX{} 发行版自带的
%     文鼎楷体，\emph{不支持 \pdfLaTeX}。
%   \item[windows] 使用 Windows 系统下的中易字体和微软雅黑字体。
%     当使用 (pdf)\LaTeX{} 编译时，微软雅黑仅在以下两种情形有效：
%     安装有 \pkg{zhmCJK} 宏包且选项 \opt{zhmap=zhmCJK} 时，或者
%     安装有微软雅黑的 Type1 字体且选项 \opt{zhmap=false} 时。
% \end{optdesc}
%
% 如果不想使用 \CTeX{} 预定义的中文字库，可以设置 \opt{fontset} 为下述值之一。
%
% \begin{optdesc}
%   \item[none] 不配置中文字体，需要用户自己配置。
%   \item[\meta{name}] 这里 \meta{name} 为自定义的名字。
%   \CTeX{} 宏集将载入名为 |ctex-fontset-|\meta{name}|.def| 的文件作为字体配置
%   文件。因此，请先保证文件的存在。可以在当前工作目录或者本地 \texttt{TDS} 目录
%   树下合适位置建立一个名为 |ctex-fontset-|\meta{name}|.def| 的文件，在这个文件
%   里面自定义中文字体。然后通过使用 |fontset=|\meta{name} 选项来调用它。字体配置
%   文件的具体写法可以参考 \CTeX{} 宏集 \texttt{fontset} 目录下的字体配置文件。
% \end{optdesc}
%
% 注意：\emph{如果希望使用 \tn{ctexset} 在导言区指定字库，则需要先在宏包/文档类选项中指定
% \opt{fontset = none}}（这会禁用 \CTeX{} 宏集的操作系统检测功能和自动设定字库功能）。例如：
% \begin{ctexexam}
%   \documentclass[fontset = none]{ctexart}
%   \ctexset{fontset = founder}
%   \begin{document}
%   在文档类选项中声明 \verb|fontset = none|，随后在导言区用 \verb|\ctexset|
%   指定字体。
%   \end{document}
% \end{ctexexam}
%
% \CTeX{} 宏集预定义的中文字库还定义了一些字体命令。除了在 \opt{ubuntu} 字库中没有
% \tn{fangsong} 的定义外，所有字库都有以下四个字体命令：
% \begin{optdesc}
%   \item[\tn{songti}] 宋体，CJK 等价命令 |\CJKfamily{zhsong}|。
%   \item[\tn{heiti}] 黑体，CJK 等价命令 |\CJKfamily{zhhei}|。
%   \item[\tn{fangsong}] 仿宋，CJK 等价命令 |\CJKfamily{zhfs}|。
%   \item[\tn{kaishu}] 楷书，CJK 等价命令 |\CJKfamily{zhkai}|。
% \end{optdesc}
% 在 \opt{windows}、\opt{founder} 和 \opt{macnew} 字库中，额外定义了 \tn{lishu}
% 和 \tn{youyuan}：
% \begin{optdesc}
%   \item[\tn{lishu}] 隶书，CJK 等价命令 |\CJKfamily{zhli}|。
%   \item[\tn{youyuan}] 圆体，CJK 等价命令 |\CJKfamily{zhyou}|。
% \end{optdesc}
% 在 \opt{windows} 字库中还定义了 \tn{yahei}。出于兼容性的考虑，\tn{yahei} 命令
% 在 \opt{macnew} 字库中也有定义，但实际调用苹方黑体：
% \begin{optdesc}
%   \item[\tn{yahei}] 微软雅黑，CJK 等价命令 |\CJKfamily{zhyahei}|。
% \end{optdesc}
% 在 \opt{macnew} 字库中，还定义了 \tn{pingfang}：
% \begin{optdesc}
%   \item[\tn{pingfang}] 苹方黑体，CJK 等价命令 |\CJKfamily{zhpf}|。
% \end{optdesc}
%
% \section{排版格式设定}
% \label{sec:format-settings}
% \subsection{文档默认字号}
% \label{subs:options-class}
%
% \begin{function}[rEXP,added=2015-05-06]{zihao}
%   \begin{syntax}
%     zihao = &lt;-4|5|false&gt;
%   \end{syntax}
%   将文章默认字号（\tn{normalsize}）设置为小四号字或五号字，
%   具体情况见表 \ref{tab:fontsize}。\opt{false} 禁用本功能。
%   本选项可以用于四个 \CTeX{} 文档类和 \pkg{ctex} 宏包，
%   也可以用于 \pkg{ctexsize} 宏包。
%
%   该选项的默认值与 \opt{scheme} 的取值有关。
%   当 \opt{scheme = chinese} 时，对标准文档类默认值为 |5|，即设置
%   \tn{normalsize} 为五号字；对 \cls{beamer} 则为 |false|，使用文档类原有的设置。
%   当 \opt{scheme = plain} 时，该选项不设默认值，沿用标准文档类或 \cls{beamer} 的原有设置。
% \end{function}
%
% \begin{table}[htbp]
% \centering
% \setlength\tabcolsep{1em}
% \caption{标准字体命令与字号的对应}\label{tab:fontsize}
% \begin{tabular}{l*2{c&gt;{\ttfamily}r}*3{&gt;{\ttfamily}c}}
% \toprule
% &amp; \multicolumn2c{|zihao = 5|} &amp; \multicolumn2c{|zihao = -4|} &amp;
% \multicolumn1c{|10pt|} &amp; \multicolumn1c{|11pt|} &amp; \multicolumn1c{|12pt|} \\
% \cmidrule(lr){2-3} \cmidrule(lr){4-5}
% \cmidrule(lr){6-6} \cmidrule(lr){7-7} \cmidrule(lr){8-8}
% 字体命令        &amp; 字号 &amp; \si{bp} &amp; 字号 &amp; \si{bp}
%                        &amp; \si{pt} &amp; \si{pt} &amp; \si{pt} \\
% \midrule
% |\tiny|         &amp; 七号 &amp; 5.5  &amp; 小六 &amp; 6.5  &amp; ~5 &amp; ~6 &amp; ~6 \\
% |\scriptsize|   &amp; 小六 &amp; 6.5  &amp; 六号 &amp; 7.5  &amp; ~7 &amp; ~8 &amp; ~8 \\
% |\footnotesize| &amp; 六号 &amp; 7.5  &amp; 小五 &amp; 9~~  &amp; ~8 &amp; ~9 &amp; 10 \\
% |\small|        &amp; 小五 &amp; 9~~  &amp; 五号 &amp; 10.5 &amp; ~9 &amp; 10 &amp; 11 \\
% |\normalsize|   &amp; 五号 &amp; 10.5 &amp; 小四 &amp; 12~~ &amp; 10 &amp; 11 &amp; 12 \\
% |\large|        &amp; 小四 &amp; 12~~ &amp; 小三 &amp; 15~~ &amp; 12 &amp; 12 &amp; 14 \\
% |\Large|        &amp; 小三 &amp; 15~~ &amp; 小二 &amp; 18~~ &amp; 14 &amp; 14 &amp; 17 \\
% |\LARGE|        &amp; 小二 &amp; 18~~ &amp; 二号 &amp; 22~~ &amp; 17 &amp; 17 &amp; 20 \\
% |\huge|         &amp; 二号 &amp; 22~~ &amp; 小一 &amp; 24~~ &amp; 20 &amp; 20 &amp; 25 \\
% |\Huge|         &amp; 一号 &amp; 26~~ &amp; 一号 &amp; 26~~ &amp; 25 &amp; 25 &amp; 25 \\
% \bottomrule
% \end{tabular}
%\end{table}
%
% \begin{function}[rEXP]{10pt, 11pt, 12pt}
%   \CTeX{} 文档类是在 \LaTeX{} 标准文档类之上开发的。因此，除了可以使用 \CTeX{}
%   宏包定义的字号选项之外，还可以使用标准文档类的同类选项（\opt{10pt}、\opt{11pt}
%   和 \opt{12pt}）。在使用这些来自标准文档类的选项的时候，\CTeX{} 文档类的字号
%   选项会被抑制。亦即，在 \opt{zihao} 选项之后设置 \opt{10pt} 选项，
%   \opt{zihao} 选项将不再起作用。
% \end{function}
%
% 标准文档类的其他选项在 \CTeX{} 文档类中依旧有效。例如，设置纸张大小和方向的
% \opt{a4paper} 和 \opt{landscape}，设置单双面的 \opt{oneside} 和
% \opt{twoside} 等。\CTeX{} 会将这些选项传给标准文档类^^A
% \footnote{事实上，\LaTeX{} 在文档类中的选项是全局设定的，除了对使用的文档类有
% 影响外，也可能会影响到随后使用的宏包。如果这些宏包中有某些选项出现在文档类的
% 选项列表中，那么该选项将会被自动激活。}。
%
% \subsection{章节标题风格}
% \label{subs:options-heading}
%
% \begin{function}[rEXP,added=2014-03-08]{heading}
%   \begin{syntax}
%     heading = &lt;\TFF&gt;
%   \end{syntax}
%   本选项只能在调用 \pkg{ctex.sty} 时作为宏包选项使用。
%
%   \CTeX{} 宏集提供了一套用于修改文档章节标题格式的接口。该选项用于选择是否
%   启用该功能。详细的设置方法请参见第 \ref{subs:pagestyle}~节和第 \ref{sec:secstyle}~节。
% \end{function}
%
% \CTeX{} 宏集提供的四个文档类总是启用该功能。如果在 \pkg{ctex.sty} 下启用该选项，
% 将会检查当前是否使用 \LaTeX{} 标准文档类。
% 若然，则该选项将会使得 \pkg{ctex.sty} 宏包的行为和 \CTeX{} 宏集提供的
% 四个中文文档类\emph{完全}一致；若不然，则会根据 \tn{chapter}
% 是否有定义来使用 \cls{ctexbook} 或者 \cls{ctexart} 的标题设置。
%
% \begin{function}[rEXP]{sub3section, sub4section}
%   修改 \tn{paragraph} 和 \tn{subparagraph} 的格式。
%
%   默认情况下，\tn{paragraph} 和 \tn{subparagraph} 会将标题与随后的正文
%   排版在同一个段落。启用 \opt{sub3section} 会将 \tn{paragraph} 的格式修改为
%   类似 \tn{section} 的格式，并将 \tn{subparagraph} 的格式修改为原本 \tn{paragraph}
%   的格式。启用 \opt{sub4section} 会将 \tn{paragraph} 和 \tn{subparagraph} 的格式
%   都修改为类似 \tn{section} 的格式。
%
%   启用该选项通常还需要将计数器 |secnumdepth| 的值为设置为 |4| 或 |5|。
%
%   具体格式可参考 \ref{subsec:sec-spacing}~小节中的 \opt{runin} 和 \opt{afterskip} 选项。
%
%   注意，上述两个选项只有在非 \cls{beamer} 文档类下 \opt{heading} 选项启用的时候
%   才有意义。亦即，只有在使用除了 \cls{ctexbeamer} 的三个 \CTeX{} 文档类或启用了
%   \opt{heading} 的 \pkg{ctex.sty} 的时候才有意义。
% \end{function}
%
% \subsection{排版方案选项}
% \label{subs:options-type-style}
%
% \begin{function}[rEXP,added=2015-04-15]{scheme}
%   \begin{syntax}
%     scheme = &lt;(chinese)|plain&gt;
%   \end{syntax}
%   选择文章的排版方案，预设有 \opt{chinese} 和 \opt{plain} 两种方案。
% \end{function}
%   \begin{optdesc}[itemsep=\medskipamount]
%     \item[chinese] 对 \cls{beamer} 以外的文档类，调整默认字号为五号字，并调
%       整行距为 |1.3|；汉化文档中的标题名字（如“图”、“表”、“目录”和“参
%       考文献”等，见 \ref{subs:capname}~节）；
%       在 \opt{heading = true} 的情况下^^A
%       \footnote{使用 \CTeX{} 文档类，或者使用 \pkg{ctex} 宏包且开启该选项时。}^^A
%       （\ref{subs:options-heading}~节），还会将章节标题的风格修改为
%       中文样式（见 \ref{sec:secstyle}~节）。
%
%       当关闭 \opt{heading} 选项的 \pkg{ctex} 宏包与标准文档类或其衍生文档类
%       联用时，会载入 \pkg{indentfirst} 宏包，以实现章节标题后的段首缩进。
%     \item[plain] 不调整默认字号和行距，不会汉化文档中的标题名字，也不会将章节
%       标题风格修改为中文样式，同时不会调整 \tn{pagestyle}，并禁用 \opt{autoindent}
%       选项。事实上，此时的 \CTeX{} 宏集只提供了中文支持功能，而不对文章版式进行任何修改。
%   \end{optdesc}
%
% \begin{function}[updated=2014-04-11]{punct}
%   \begin{syntax}
%     punct = &lt;(quanjiao)|banjiao|kaiming|CCT|plain&gt;
%   \end{syntax}
%   设置标点处理格式。预定义好的格式有：
% \end{function}
%   \begin{optdesc}
%     \item[quanjiao] 全角式：所有标点占一个汉字宽度，相邻两个标点占 1.5 汉字宽度；
%     \item[banjiao]  半角式：所有标点占半个汉字宽度；
%     \item[kaiming]  开明式：句末点号^^A
%       \footnote{标点符号分为标号与点号。点号分为两类，一共七种：句末点号有^^A
%       句号、问号和叹号；句内点号有逗号、顿号、冒号和分号。}用占一个汉字宽度，标^^A
%       号和句内点号占半个汉字宽度；
%     \item[CCT]   CCT 式：所有标点符号的宽度略小于一个汉字宽度；
%     \item[plain] 原样（不调整标点间距）。
%   \end{optdesc}
%
% \begin{function}[updated=2014-03-08]{space}
%   \begin{syntax}
%     space = &lt;\TF|(auto)&gt;
%   \end{syntax}
%   是否在生成的 PDF 中保留汉字后面的空格。该选项仅在使用 \XeLaTeX{}/(pdf)\LaTeX{} 编译时有效。
% \end{function}
%
% \begin{optdesc}
%   \item[true] 总是保留汉字后的空格。此时，用户需要自行在行尾加上~|%|~处理换行产生
%     的空格\footnote{\LaTeX{} 将单个换行视作一个空格。}。
%   \item[false] 使用 (pdf)\LaTeX{} 编译时：总是忽略掉汉字后面的空格，不论汉字后是什么；
%     使用 \XeLaTeX{} 编译时，等同于 \opt{auto} 的效果。不建议使用该选项。
%   \item[auto] 根据空格后面的情况决定是否保留：如果空格后面是汉字，则忽略该
%   空格，否则保留。
% \end{optdesc}
%
%   例如，使用
%   \begin{ctexexam}
%   \ctexset{space=true}
%   汉字 分词
%   技术 English
%   \end{ctexexam}
%   将得到“{\ctexset{space=true}汉字 分词 技术 English}”；使用
%   \begin{ctexexam}
%   \ctexset{space=auto}
%   汉字 分词
%   技术 English
%   \end{ctexexam}
%   则会得到“{\ctexset{space=auto}汉字 分词 技术 English}”。
%
% \emph{使用 \textup{\LuaLaTeX{} 及 \upLaTeX} 编译的时候，该选项无效：汉字间的
% 空格以及汉字与西文字符之间的空格总是有效，不会被忽略，但可以自动忽略掉由换行
% 产生的空格。}
%
% \begin{function}[rEXP,added=2014-04-23]{linespread}
%   \begin{syntax}
%     linespread = &lt;数值&gt;
%   \end{syntax}
%   接受一个浮点数值，设置行距倍数。本选项的初始值与 \opt{scheme} 有关。
% \end{function}
% \begin{optdesc}
%   \item[scheme = chinese] 对标准文档类初始值为 $1.3$，即 $1.3$ 倍行距。此
%   时，相邻两行的基线（\tn{baselineskip}）距离为 $1.3\times 1.2=1.56$ 倍字体
%   高度。对 \cls{beamer} 不改变行距，即使用默认的单倍行距。
%
%   \item[scheme = plain] \CTeX{} 宏集默认不调整行距倍数，文档中的行距由所选文档类和
%   其他宏包或用户设置决定。
% \end{optdesc}
%
% \begin{function}[added=2014-03-13]{autoindent}
%   \begin{syntax}
%     autoindent = &lt;\TTF|数值|带单位的数值&gt;
%   \end{syntax}
%   在字体大小发生变化时，是否自动调整段首缩进（\tn{parindent}）的大小。
% \end{function}
% \begin{optdesc}
%   \item[\meta{数值或带单位的数值}] 用于设置段首缩进的长度。如果不带单位，则默认
%   单位是单个汉字字宽 \tn{ccwd}；如果带单位，则使用该单位。
%   若要显式使用 \tn{ccwd} 为单位，则必须在导言区进行设置。
%
%   \item[true] 等价于设置 \opt{autoindent = 2} 或
%   在导言区设置 \opt{autoindent = 2\tn{ccwd}}。
%
%   \item[false] 禁用自动调整功能，可以设置固定长度的段首缩进。如设置每段缩进 40 点：
%   \begin{ctexexam}
%   \ctexset{autoindent=false}
%   \setlength\parindent{40pt}
%   \end{ctexexam}
% \end{optdesc}
%
% \begin{function}[EXP,added=2014-03-26]{linestretch}
%   \begin{syntax}
%     linestretch = &lt;数值或长度&gt;
%   \end{syntax}
%   \opt{linestretch} 是一个比较特殊的选项，它用来设置汉字之间弹性间距的弹性程
%   度。如果有单位，则可以在选项中直接写；如果是数字，单位则是汉字宽度
%   \tn{ccwd} 的倍数。
% \end{function}
%
%   如果行宽不是汉字宽度的整数倍，为了让段落左右两端对齐，自然就要求伸展汉字之
%   间的间距，而 \opt{linestretch} 选项就是设置每行总的允许伸行量。初始值是允
%   许每行伸行一个汉字的宽度 \tn{ccwd}，并且此宽度能根据字号变化动态调整。
%
%   过小的 \opt{linestretch} 可能导致段落文字右侧可能参差不齐；较大的
%   \opt{linestretch} 选项则可以帮助拥有较长不可断行内容的复杂段落方便地断行，
%   而不会产生大量编译警告；但很大的 \opt{linestretch} 则会掩盖段落不良断行产
%   生的坏盒子警告。
%
%   如果将 \opt{linestretch} 选项的值设置为 \tn{maxdimen}，则可以禁止按字号自
%   动修改每行的允许伸长量。此时汉字间的弹性间距则固定为 \tn{baselineskip} 的
%   $0.08$ 倍。
%
% \section{文档汉化}
% \label{sec:chinese-localization}
% \subsection{日期汉化}
%
% \CTeX 宏包对显示当前日期的 \tn{today} 命令进行了汉化，使之以中文的方式显示今
% 天的日期。如本文档编译时的日期是“\today”。
%
% \begin{function}[EXP]{today}
%   \begin{syntax}
%     today = &lt;(small)|big|old&gt;
%   \end{syntax}
% 该选项用来控制 \tn{today} 命令的输出格式：
% \begin{optdesc}
%   \item[small] \ctexset{today=small}
%     效果为“\today”。使用阿拉伯数字和汉字的日期格式。
%   \item[big] \ctexset{today=big}
%     效果为“\today”。使用全汉字的日期格式。
%   \item[old] \ctexset{today=old}
%     效果为“\today”。使用文档原来的（英文）日期格式。
%     \ctexset{today=small}  ^^A NOTE(Liam): 复原设定是好习惯。
% \end{optdesc}
% \end{function}
%
% 设置日期格式使用 \tn{ctexset} 命令完成，例如设置全汉字的日期格式：
% \begin{ctexexam}
%   \ctexset{today=big}
% \end{ctexexam}
%
% \CTeX 宏包的中文日期功能实际上是调用 \pkg{zhnumber} 宏包完成的。如果需要更
% 多有关日期、时间的命令和更复杂的设置，可以查阅 \pkg{zhnumber} 宏包的文档。
%
% \subsection{文档标题汉化}
% \label{subs:capname}
%
% 这里主要介绍由 \opt{scheme} 选项（\ref{subs:options-type-style}~节）控制
% 的文档标题汉化功能。
%
% 设置文档标题名的示例可见例~\ref{exam:capname}。下面的选项（如
% \opt{contentsname}）主要用来重新定义与选项同名的宏（如 \tn{contentsname}）的
% 定义。
%
% \begin{defaultcapconfig}
%
% \begin{function}[EXP]{contentsname}
%   \begin{syntax}
%     contentsname = &lt;名字&gt;
%   \end{syntax}
% 设置目录标题名 \tn{contentsname}。中文默认为“\contentsname”。
% \end{function}
%
% \begin{function}[EXP]{listfigurename}
%   \begin{syntax}
%     listfigurename = &lt;名字&gt;
%   \end{syntax}
% 设置插图目录标题名 \tn{listfigurename}。中文默认为“\listfigurename”。
% \end{function}
%
% \begin{function}[EXP]{listtablename}
%   \begin{syntax}
%     listtablename = &lt;名字&gt;
%   \end{syntax}
% 设置表格目录标题名 \tn{listtablename}。中文默认为“\listtablename”。
% \end{function}
%
% \begin{function}[EXP]{figurename}
%   \begin{syntax}
%     figurename = &lt;名字&gt;
%   \end{syntax}
% 设置图片环境标题名 \tn{figurename}。中文默认为“\figurename”。
% \end{function}
%
% \begin{function}[EXP]{tablename}
%   \begin{syntax}
%     tablename = &lt;名字&gt;
%   \end{syntax}
% 设置表格环境标题名 \tn{tablename}。中文默认为“\tablename”。
% \end{function}
%
% \begin{function}[EXP]{abstractname}
%   \begin{syntax}
%     abstractname = &lt;名字&gt;
%   \end{syntax}
% 设置摘要 \env{abstract} 环境标题名 \tn{abstractname}。中文默认
% 为“\abstractname”。注意 \cls{book} 类没有摘要，该选项无效。
% \end{function}
%
% \begin{function}[EXP]{indexname}
%   \begin{syntax}
%     indexname = &lt;名字&gt;
%   \end{syntax}
% 设置索引标题名 \tn{indexname}。中文默认为“\indexname”。
% \end{function}
%
% \begin{function}[EXP]{appendixname}
%   \begin{syntax}
%     appendixname = &lt;名字&gt;
%   \end{syntax}
% 设置附录标题名 \tn{appendixname}。中文默认为“\appendixname”。
% \end{function}
%
% \begin{function}[EXP]{bibname}
%   \begin{syntax}
%     bibname = &lt;名字&gt;
%   \end{syntax}
% 设置参考文献标题名。中文默认为“\refname”。
%
% 在标准文档类中 \cls{article} 的参考文献名使用宏 \tn{refname}，而
% \cls{book} 和 \cls{report} 使用宏 \tn{bibname}。本选项会根据标准文档类的不同，自动
% 设定 \tn{refname} 或是 \tn{bibname}。因此，对于标准文档类及对应的 \CTeX{} 文档类
% 可以统一地使用 \opt{bibname} 选项来控制参考文献标题名。
%
% 对于 \cls{beamer} 及对应的 \cls{ctexbeamer} 来说，它们同时具有宏 \tn{bibname} 和
% 宏 \tn{refname}。本选项仅控制其中的 \tn{bibname}；
% \tn{refname} 则交由 \opt{refname} 选项控制。
% \end{function}
%
% \begin{function}[EXP]{proofname}
%   \begin{syntax}
%     proofname = &lt;名字&gt;
%   \end{syntax}
% 设置证明环境的名称 \tn{proofname}。中文默认为“\proofname”。
% \end{function}
%
% 如果使用 \cls{ctexbeamer} 文档类或者在 \cls{beamer} 文档类下使用 \pkg{ctex} 包，
% 还会汉化常用定理类环境的诸如“定义”、“定理”和“引理”等名称。此时，还有下列
% 三个选项。
%
% \begin{function}[EXP]{refname}
%   \begin{syntax}
%     refname = &lt;名字&gt;
%   \end{syntax}
% 设置参考文献标题名 \tn{refname}。中文默认为“\refname”。
%
% 注意，三个标准文档类（及相应的 \CTeX{} 文档类）的参考文献标题名由 \opt{bibname} 选项
% 统一设置，本选项仅适用于 \cls{beamer} 及其对应的 \cls{ctexbeamer}。
% 在三个标准文档类（及相应的 \CTeX{} 文档类）中使用 \opt{refname} 选项会报错。
% \end{function}
%
% \begin{function}[EXP]{algorithmname}
%   \begin{syntax}
%     algorithmname = &lt;名字&gt;
%   \end{syntax}
% 设置算法环境标题名 \tn{algorithmname}。中文默认为“算法”。
% \end{function}
%
% \begin{function}[EXP]{continuation}
%   \begin{syntax}
%     continuation = &lt;名字&gt;
%   \end{syntax}
% 设置 \cls{beamer} 可断页的帧在续页标题中的延续标识 \tn{insertcontinuationtext}。
% 中文默认为“（续）”。
% \end{function}
%
% \end{defaultcapconfig}
%
% \subsection{页面格式设置与汉化}
% \label{subs:pagestyle}
%
% 页面格式设置与汉化的功能（及章节标题样式设置功能，见第 \ref{sec:secstyle} 节）^^A
% 由 \pkg{ctexheading} 宏包完成。加载该宏包时，或者使用 \CTeX{} 文档类时，^^A
% 或者是使用 \pkg{ctex} 宏包并设定选项 \opt{heading = true} 时，相关功能被激活。
% 此时，整个文档的页面格式（page style）被设定为 |headings|，即相当于设置了
% \begin{frameverb}
%   \pagestyle{headings}
% \end{frameverb}
% 在页眉中显示当前章节的编号与标题。
%
% 同时，\CTeX 宏包也会对默认的 |headings| 页面格式进行修改，使之调用
% \tn{CTEXthechapter}、\tn{CTEXthesection} 等宏来正确显示中文的章节编号。
%
% \CTeX 宏包的默认页面格式设置是经过汉化的 |headings|，其基本效果如本文档所
% 示，只在页眉一侧显示章节编号和标题，另一侧显示页码。
%
% 更复杂的页面格式可以通过调用 \pkg{fancyhdr}、\pkg{titleps} 等宏包来设
% 置。\CTeX 宏包同时也为这些自定义页面格式
% 的包提供了以下宏供使用：
% \begin{itemize}
% \item \tn{CTEXthechapter}、\tn{CTEXthesection} 等章节编号（见
% \ref{subsec:sec-commands}~小节）。它们用来代替英文文档类中的
% \tn{thechapter}、\tn{thesection} 等宏。
%
% \item \tn{leftmark}、\tn{rightmark}，它们是在使用章节标题命令后，自动设置的
% 宏。它们实际是在与章节标题命令对应的标记命令
% \tn{chaptermark}、\tn{sectionmark} 中调用 \tn{markright} 或 \tn{markboth} 生
% 成的。
% \end{itemize}
% 有关 \LaTeX 页面标记的含义与使用细节，已经超出了本文档讨论的范围。可以参考
% \cite[Chapter~23]{knuthtex1986}、\cite[\S4.3, \S4.4]{mittelbach2004} 等书籍。
%
% 这里举一个例子，说明通过重定义 \tn{sectionmark}，在 \cls{ctexart} 文档类中的
% 标准 |headings| 页面格式下控制页眉的方式：
% \begin{ctexexam}
%   \documentclass{ctexart}
%   \pagestyle{headings}
%   \ctexset{section={
%       name={第,节},
%       number=\arabic{section},
%     }
%   }
%   \renewcommand\sectionmark[1]{%
%     \markright{\CTEXifname{\CTEXthesection——}{}#1}}
%
%   \begin{document}
%
%   \section{天地玄黄}
%   \newpage
%
%   \section{宇宙洪荒}
%
%   \end{document}
% \end{ctexexam}
% 在上例中，我们设置了页眉的形式是用破折号分开的节编号与节标题，即“第 1 节
% ——天地玄黄”、“第 2 节——宇宙洪荒”。
%
% \CTeX 宏包已经对 \pkg{fancyhdr} 宏包进行了补丁，载入 \pkg{fancyhdr} 后，其
% |fancy| 页面格式将使用 \tn{CTEXthechapter} 等宏显示中文章节编号。
%
% 关于 \pkg{fancyhdr} 的具体用法可以参见其宏包手册。通常也只要像在标准的英文文
% 档类中使用 \pkg{fancyhdr} 一样定义页眉页脚格式即可，并不需要额外的定义。
%
% 下面我则给出一个与前例类似而稍复杂的例子，展示如何在文档中设置页眉内容与页眉
% 的格式。
% \begin{ctexexam}
%   \documentclass{ctexart}
%   \ctexset{section={
%       name={第,节},
%       number=\arabic{section},
%     }
%   }
%   \usepackage{fancyhdr}
%   \fancyhf{}
%   \lhead{\textnormal{\kaishu\rightmark}}
%   \rhead{--\ \thepage\ --}
%   \pagestyle{fancy}
%   % \sectionmark 的重定义需要在 \pagestyle 之后生效
%   \renewcommand\sectionmark[1]{%
%     \markright{\CTEXifname{\CTEXthesection——}{}#1}}
%
%   \begin{document}
%
%   \section{天地玄黄}
%   \newpage
%
%   \section{宇宙洪荒}
%
%   \end{document}
% \end{ctexexam}
% 本例的页眉效果大致如下（有页眉线）：
% \begin{trivlist}\item
% \textnormal{\kaishu 第 1 节——天地玄黄}\hfill -- 1 --\par
% \smallskip\hrule
% \end{trivlist}
%
% \section{章节标题样式设置}
% \label{sec:secstyle}
%
% \CTeX{} 宏集对 \LaTeX{} 的标准文档类（\cls{article}、\cls{report}、
% \cls{book}）和 \cls{beamer} 进行了章节标题样式设置功能的扩充。
% 章节标题样式设置功能（及页面格式设置与汉化功能，见第 \ref{subs:pagestyle} 节）^^A
% 由 \pkg{ctexheading} 宏包完成。加载该宏包时，或者使用 \CTeX{} 文档类时，^^A
% 或者是使用 \pkg{ctex} 宏包并设定选项 \opt{heading = true} 时，相关功能被激活。
% 其中，独立使用 \pkg{ctexheading} 宏包时，本节介绍各选项的默认值与指定
% \opt{scheme = plain} 时相同。
%
% 本节涉及的所有选项均需使用 \tn{ctexset} 命令设置。
%
% \changes{v2.0}{2015/03/21}{\tn{CTEXsetup}, \tn{CTEXoptions} 是过时命令。}
%
% 章节标题的样式选项是分层设置的。顶层的选项是章节标题名称（例如 |section|)，
% 次一层的选项是章节标题的样式（例如 \opt{nameformat}）。章节标题名称包括
% |part|, |chapter|, |section|, |subsection|, |subsubsection|, |paragraph|,
% |subparagraph|。可用的样式选项包括：
% \begin{itemize}
%   \item 编号相关（\ref{subsec:sec-number}~小节）：
%     \opt{numbering}, \opt{name}, \opt{number}
%   \item 格式相关（\ref{subsec:sec-format}~小节）：
%     \opt{format}, \opt{nameformat}, \opt{numberformat}, \opt{titleformat},
%     \opt{aftername}, \opt{aftertitle}, \opt{pagestyle}
%   \item 间距、缩进相关（\ref{subsec:sec-spacing}~小节）：
%     \opt{runin}, \opt{hang}, \opt{indent}, \opt{beforeskip}, \opt{afterskip},
%     \opt{fixskip}, \opt{break}, \opt{afterindent}
%   \item 目录、附录相关（\ref{subsec:sec-toc-appendix}~小节）：
%     \opt{tocline}, \opt{lofskip}, \opt{lotskip}, \opt{appendix/numbering},
%     \opt{appendix/name}, \opt{appendix/number}
% \end{itemize}
%
% 注意，对 \cls{article} 及其衍生的 \cls{ctexart} 等文档类，没有 |chapter|
% 级别的标题；而对于 \cls{beamer} 文档类，这些选项控制的是由 \tn{partpage},
% \tn{sectionpage} 和 \tn{subsectionpage} 产生的标题样式，此时只有 |part|,
% |section| 和 |subsection| 这三层级别，并且 \opt{runin}, \opt{afterindent},
% \opt{fixskip}, \opt{hang}, \opt{break} 和 \opt{tocline} 这六个选项无效。
%
% 多层选项之间用斜线分开，例如，\opt{part/name} 选项设置 \tn{part} 标题的在数
% 字前后的名称，而 \opt{section/number} 选项设置 \tn{section} 标题的数字类型。
%
% 使用 \tn{ctexset} 设置多级选项时，还可以在同一个上级选项下设置多个下级选项。
% 例如，同时设置 |part| 一级标题的 \opt{pagestyle} 选项，|chapter| 一级标题的
% \opt{format} 与 \opt{pagestyle} 选项和 |section| 一级标题的 \opt{name} 与
% \opt{number} 选项：
% \begin{ctexexam}
%   \ctexset {
%     part/pagestyle = empty,
%     chapter = {
%       format    = \raggedright,
%       pagestyle = empty,
%     },
%     section = {
%       name   = {第,节},
%       number = \chinese{section},
%     }
%   }
% \end{ctexexam}
%
% \subsection{编号相关}
% \label{subsec:sec-number}
%
% \begin{function}[EXP,added=2015-06-21]{part/numbering, chapter/numbering,
%   section/numbering, subsection/numbering, subsubsection/numbering,
%   paragraph/numbering, subparagraph/numbering}
%   \begin{syntax}
%     numbering = \TTF
%   \end{syntax}
%   控制是否对\emph{不带星号}的章节标题进行编号。
%   各级标题的默认值均为 \opt{true}。
%
%   \LaTeX{} 标准的章节标题命令（如 \tn{section}）大体上完成四项工作：
%   输出标题内容、对标题编号（计数器增加 1）、将标题列入目录（若调用了
%   \pkg{hyperref} 宏包还会添加 PDF 书签）、更新页眉页脚标记。带星号的
%   章节标题命令（如 \tn{section*}）只简单地输出章节标题内容，但不对标题编号，
%   不将标题列入目录或 PDF 书签，也不写入页眉页脚标记。与之不同的是，
%   本选项仅仅是否对\emph{不带星号}的章节标题进行编号。因此，当设置本选项为
%   \opt{false} 时，除了不对标题编号以外，其余功能与正常标题一致：可以
%   编入目录，并生成正确的 \pkg{hyperref} 目录超链接位置和页眉页脚标记。例如：
%   \begin{ctexexam}
%   \documentclass{ctexbook}
%   \begin{document}
%   \tableofcontents
%   \chapter{A}
%   \chapter*{B}
%   \ctexset{chapter/numbering=false}
%   \chapter{C}
%   \end{document}
%   \end{ctexexam}
%   三章的标题分别为“第一章\quad A”、“B”和“C”，但在目录中则只出现
%   “第一章\quad A”和“C”。
%
%   注意，章节标题是否编号还要受到 \LaTeX{} 计数器 |secnumdepth| 的控制^^A
%   （可通过以下介绍的 \opt{secnumdepth} 选项设置）。
%   例如，对于 |section| 而言，其深度为 1。因此，|section| 会被编号，当且仅当
%   |secnumdepth| 不小于 1，并且 \opt{section/numbering} 为 \opt{true}，
%   并且使用不带星号的章节标题命令（即 \tn{section}）。
% \end{function}
%
% \begin{function}[EXP,added=2020-05-06]{secnumdepth}
%   \begin{syntax}
%     secnumdepth = &lt;整数或章节名称&gt;
%   \end{syntax}
%   设置对章节标题进行编号的层次数。\opt{secnumdepth} 的值可以是一个整数，也可以是
%   |part|, |chapter| 等名称。
%   层次数与名称的对应关系见表~\ref{tab:heading-level}。
%   章节层次的默认设置见表~\ref{tab:heading-level-default}。
%
%   本选项对 \cls{beamer}/\cls{ctexbeamer} 文档类无效。
% \end{function}
%
% \begin{table}[htbp]
% \begin{minipage}[t]{.43\linewidth}
%   \small\centering
%   \caption{章节层次}
%   \label{tab:heading-level}
%   \begin{tabular}{rll}
%   \toprule
%   层次 &amp; 名称 &amp; 注 \\
%   \midrule
%   |-1| &amp; part    &amp; \cls{book}/\cls{report} 类 \\
%    |0| &amp; chapter &amp; \cls{book}/\cls{report} 类 \\
%    |0| &amp; part    &amp; \cls{article} 类   \\
%    |1| &amp; section \\
%    |2| &amp; subsection \\
%    |3| &amp; subsubsection \\
%    |4| &amp; paragraph \\
%    |5| &amp; subparagraph \\
%   \bottomrule
%   \end{tabular}
% \end{minipage}^^A
% \begin{minipage}[t]{.57\linewidth}
%   \small\centering
%   \caption{章节层次的默认设置}
%   \label{tab:heading-level-default}
%   \begin{tabular}{lll}
%   \toprule
%   文档类 &amp; \opt{secnumdepth} &amp; \opt{tocdepth} \\
%   \midrule
%   \cls{article}           &amp; |3| (subsubsection) &amp; |3| (subsubsection) \\
%   \cls{book}/\cls{report} &amp; |2| (subsection)    &amp; |2| (subsection) \\
%   \cls{beamer}            &amp; 无效 &amp; |3| (subsubsection) \\
%   \bottomrule
%   \end{tabular}
% \end{minipage}
% \end{table}
%
%   如果没有特别说明，以下将用 “|...|” 代表各级章节标题名。
%
% \begin{function}[EXP,updated=2014-03-08]{.../name}
%   \begin{syntax}
%     name = \{&lt;前名字&gt;,&lt;后名字&gt;\}
%     name = \Arg{前名字}
%   \end{syntax}
%   设置章节的名字。所谓“章节的名字”，可以分为前后两部分，即章节编号前后的
%   词语，两个词之间用一个半角逗号分开；也可以只有一部分，表示只有章节编号之前
%   的名字。例如：
%   \begin{ctexexam}
%   \ctexset{
%     chapter/name = {第,章},
%     section/name = {\S},
%   }
%   \end{ctexexam}
%   会使得 \tn{chapter} 标题使用形如“第一章”的名字，而 \tn{section} 标题则使
%   用形如“\S1”的名字。该选项的默认设置见表~\ref{tab:name-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \setlength\leftskip{0pt plus 1 fil minus \marginparwidth}
%   \caption{\opt{name} 选项的默认设置}
%   \label{tab:name-default}
%   \begin{tabular}{llll}
%   \toprule
%   标题名 &amp; \opt{scheme = chinese} &amp; \opt{scheme = plain} &amp; 注 \\
%   \midrule
%   part &amp; |{第,部分}| &amp; |{\partname\space}| &amp; 原 \tn{partname} 为 Part \\
%   chapter &amp; |{第,章}| &amp; |{\chaptername\space}|
%     &amp; 原 \tn{chaptername} 为 Chapter \\
%   section (beamer) &amp; |{}| &amp; |{\sectionname\space}|
%     &amp; \BSTACK 原 \tn{sectionname} 为\\ |\translate{Section}| \ESTACK \\
%   section &amp; 同右 &amp; |{}| &amp; \\
%   subsection (beamer) &amp; |{}| &amp; |{\subsectionname\space}|
%     &amp; \BSTACK 原 \tn{subsectionname} 为\\ |\translate{Subsection}| \ESTACK \\
%   subsection &amp; 同右 &amp; |{}| &amp; \\
%   subsubsection &amp; 同右 &amp; |{}| &amp; \\
%   paragraph &amp; 同右 &amp; |{}| &amp; \\
%   subparagraph &amp; 同右 &amp; |{}| &amp; \\
%   \bottomrule
%   \end{tabular}
% \end{table}
%
% \begin{function}[EXP]{.../number}
%   \begin{syntax}
%     number = \Arg{数字输出命令}
%   \end{syntax}
%   设置章节编号的数字输出格式。\meta{数字输出命令} 通常是对应章节编号计数器的
%   输出命令，如 \tn{thesection} 或 |\chinese{chapter}| 之类。例如：
%   \begin{ctexexam}
%   \ctexset{
%     section/number = \Roman{section}
%   }
%   \end{ctexexam}
%   将会使 \tn{section} 的编号变为大写罗马数字（如 I、II 等）。
%
%   \opt{number} 选项定义的同时将控制对章节计数器的交叉引用。在引用计数器时，
%   记录在 \LaTeX{} 辅助文件中的是 \opt{number} 选项的定义。
%
%   但是，\opt{number} 选项不会影响计数器本身的输出。即设置 |section/number|
%   不会影响 \tn{thesection} 的定义（但该选项会影响 \tn{CTEXthesection} 的定
%   义，见后）。该选项的默认设置见表~\ref{tab:number-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \caption{\opt{number} 选项的默认设置}
%   \label{tab:number-default}
%   \setlength\leftskip{0pt plus 1 fil minus \marginparwidth}
%   \begin{tabular}{llll}
%   \toprule
%   标题名 &amp; \opt{scheme = chinese} &amp; \opt{scheme = plain}
%     &amp; 原 |\the|\meta{标题} 等价定义 \\
%   \midrule
%   part (beamer) &amp; |\chinese{part}| &amp; |\insertromanpartnumber| &amp; 意义为 |\Roman{part}| \\
%   part &amp; |\chinese{part}| &amp; |\thepart| &amp; |\Roman{part}| \\
%   chapter &amp; |\chinese{chapter}| &amp; |\thechapter| &amp; |\arabic{chapter}| \\
%   section (beamer) &amp; 同右 &amp; |\insertsectionnumber| &amp; 意义为 |\arabic{section}| \\
%   section &amp; 同右 &amp; |\thesection| &amp; |\arabic{section}| \\
%   subsection (beamer)
%     &amp; \BSTACK |\arabic{section}.|\\ |\arabic{subsection}| \ESTACK
%     &amp; |\insertsubsectionnumber| &amp; 意义为 |\arabic{subsection}| \\
%   subsection &amp; 同右 &amp; |\thesubsection| &amp; |\thesection.\arabic{subsection}| \\
%   subsubsection &amp; 同右 &amp; |\thesubsubsection|
%     &amp; |\thesubsection.\arabic{subsubsection}| \\
%   paragraph &amp; 同右 &amp; |\theparagraph|
%     &amp; |\thesubsubsection.\arabic{paragraph}| \\
%   subparagraph &amp; 同右 &amp; |\thesubparagraph|
%     &amp; |\theparagraph.\arabic{subparagraph}| \\
%   \bottomrule
%   \end{tabular}
% \end{table}
%
% \subsection{格式相关}
% \label{subsec:sec-format}
%
% \CTeX{} 宏集提供了 \opt{numberformat}, \opt{nameformat}, \opt{titleformat},
% \opt{format} 这几个选项用来控制章节标题的格式。
% 它们的作用范围如图~\ref{fig:heading-format} 所示。具体用法见下文。
%
% \begin{figure}[htbp]
%   \centering
%   \[
%     \underbrace{
%       \overbrace{
%         \text{\huge\bfseries 第}
%         \mspace{-25mu}
%         \underbrace{\text{\huge\bfseries 1}}_{\text{\small\opt{numberformat}}}
%         \mspace{-25mu}
%         \text{\huge\bfseries 章}
%       }^{\text{\small\opt{nameformat}}} \quad
%       \overbrace{\text{\huge\bfseries 熟悉 \LaTeX}}^{\text{\small\opt{titleformat}}}
%     }_{\text{\small\opt{format}}}
%   \]
%   \caption{\opt{numberformat}, \opt{nameformat}, \opt{titleformat},
%     \opt{format} 几个选项的作用范围示意}
%   \label{fig:heading-format}
% \end{figure}
%
% \begin{function}[EXP,updated=2020-04-22]{.../format, .../format+}
%   \begin{syntax}
%     format = \Arg{格式命令}
%     format+= \Arg{格式命令}
%   \end{syntax}
%   \opt{format} 选项用于控制章节标题的全局格式，作用域为章节名字和随后的标题
%   内容。可以用于控制章节标题的对齐方式、整体字体字号等格式。
%   带加号的 \opt{format+} 选项用于在已有的格式命令后附加内容。
%
%   \opt{format} 选项的最后一个格式命令可以带有一个参数。
%   这一参数用于接受章节名字、编号和标题内容（以及由 \opt{nameformat}, \opt{numberformat},
%   \opt{aftername}, \opt{titleformat}, \opt{aftertitle}, \opt{indent}
%   及 \opt{hang} 选项设定的，应用于这些内容之上的格式），以实现特殊效果。
%
%   例如，设置章标题为无衬线字体左对齐、为节标题增加无衬线字体设置、
%   为小节标题加框（\tn{fbox} 命令本身需带一个参数）：
%   \begin{ctexexam}
%   \ctexset{
%     chapter/format     = \sffamily\raggedright,
%     section/format    += \sffamily,
%     subsection/format += \fbox,
%   }
%   \end{ctexexam}
%
%   \opt{format} 选项的默认设置见表~\ref{tab:format-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \begin{threeparttable}
%     \caption{\opt{format} 选项的默认设置}
%     \label{tab:format-default}
%     \begin{tabular}{lll}
%     \toprule
%     标题名 &amp; \opt{scheme = chinese} &amp; \opt{scheme = plain} \\
%     \midrule
%     part (article) &amp; |\Large\bfseries\centering| &amp; |\raggedright|\tnote{*} \\
%     part (beamer) &amp; 同右 &amp; |\centering| \\
%     part &amp; |\huge\bfseries\centering| &amp; |\centering| \\
%     chapter &amp; |\huge\bfseries\centering| &amp; |\raggedright| \\
%     section (beamer) &amp; 同右 &amp; |\centering| \\
%     section &amp; |\Large\bfseries\centering| &amp; |\Large\bfseries| \\
%     subsection (beamer) &amp; 同右 &amp; |\centering| \\
%     subsection &amp; 同右 &amp; |\large\bfseries| \\
%     subsubsection &amp; 同右 &amp; |\normalsize\bfseries| \\
%     paragraph &amp; 同右 &amp; |\normalsize\bfseries| \\
%     subparagraph &amp; 同右 &amp; |\normalsize\bfseries| \\
%     \bottomrule
%     \end{tabular}
%     \begin{tablenotes}
%       \item[*] 为了与 \LaTeXe{} 的默认效果保持一致，在 \opt{scheme = plain}
%           时，part 和 chapter 的 \opt{nameformat} 和 \opt{titleformat}
%           并不一样，因此没有使用 \opt{format} 选项统一设置名字和标题的格式。
%     \end{tablenotes}
%   \end{threeparttable}
% \end{table}
%
% \begin{function}[EXP,updated=2015-06-30]{.../nameformat, .../nameformat+}
%   \begin{syntax}
%     nameformat = \Arg{格式命令}
%     nameformat+= \Arg{格式命令}
%   \end{syntax}
%   \opt{nameformat} 用于控制章节名字的格式，作用域为章节名字，包括编号。它一
%   般用于章节名（包括编号）与章节标题的字体、字号等设置不一致的情形。参见
%   下面的 \opt{titleformat} 选项。\opt{nameformat+} 用于在已有的章节名字
%   格式命令后附加内容。
%
%   \opt{nameformat} 选项的最后一个格式命令可以带有一个参数。
%   这一参数用于接受章节名字和编号，以实现特殊效果（见例~\ref{exam:miscopt}）。
%
%   \opt{nameformat} 选项的默认设置见表~\ref{tab:nameformat-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \caption{\opt{nameformat} 选项的默认设置}
%   \label{tab:nameformat-default}
%   \begin{tabular}{lll}
%   \toprule
%   标题名 &amp; \opt{scheme = chinese} &amp; \opt{scheme = plain} \\
%   \midrule
%   part (article) &amp; |{}| &amp; |\Large\bfseries| \\
%   part (beamer) &amp; 同右
%     &amp; \BSTACK |\usebeamerfont{part name}| \\
%               |\usebeamercolor[fg]{part name}| \ESTACK \\
%   part &amp; |{}| &amp; |\huge\bfseries| \\
%   chapter &amp; |{}| &amp; |\huge\bfseries| \\
%   section (beamer) &amp; 同右
%     &amp; \BSTACK |\usebeamerfont{section name}| \\
%               |\usebeamercolor[fg]{section name}| \ESTACK \\
%   section &amp; 同右 &amp; |{}| \\
%   subsection (beamer) &amp; 同右
%     &amp; \BSTACK |\usebeamerfont{subsection name}| \\
%               |\usebeamercolor[fg]{subsection name}| \ESTACK \\
%   subsection &amp; 同右 &amp; |{}| \\
%   subsubsection &amp; 同右 &amp; |{}| \\
%   paragraph &amp; 同右 &amp; |{}| \\
%   subparagraph &amp; 同右 &amp; |{}| \\
%   \bottomrule
%   \end{tabular}
% \end{table}
%
% \begin{function}[EXP,updated=2015-06-19]{.../numberformat, .../numberformat+}
%   \begin{syntax}
%     numberformat = \Arg{格式命令}
%     numberformat+= \Arg{格式命令}
%   \end{syntax}
%   \opt{numberformat} 选项用于控制章节编号的格式，作用域仅为编号数字本身。对
%   各级标题默认均为空，当需要编号的格式和前后的章节名字不一样时可以使用。
%   \opt{numberformat+} 用于在已有的编号格式命令后附加内容。
%
%   \opt{numberformat} 选项的最后一个格式命令可以带有一个参数。这一参数用于接受
%   编号数字。例如，我们可以使用 \opt{numberformat} 特别强调章标题中的数字：
%   \begin{ctexexam}
%   \ctexset{
%     chapter/number = \arabic{chapter},
%     chapter/numberformat = \color{blue}\zihao{0}\emph,
%   }
%   \end{ctexexam}
%   上面的代码在 \opt{scheme = chinese} 时可以做出类似这样的章标题效果：
%   \begin{center}
%     \huge\bfseries 第 \emph{\color{blue}\zihao{0}4} 章
%   \end{center}
%
%   \opt{numberformat} 选项默认均设置为空，故章节编号默认与章节名字使用
%   相同的格式。
% \end{function}
%
% \begin{function}[EXP,updated=2015-06-30]{.../titleformat, .../titleformat+}
%   \begin{syntax}
%     titleformat = \Arg{格式命令}
%     titleformat+= \Arg{格式命令}
%   \end{syntax}
%   \opt{titleformat} 选项用于控制标题内容的格式，作用域为章节标题内容。
%   \opt{titleformat+} 选项用于在已有的标题格式命令后附加内容。
%
%   \opt{titleformat} 选项的最后一个格式命令可以带有一个参数。这一参数用于接受
%   标题内容。例如，实现多行标题的居中悬挂对齐：
%   \begin{ctexexam}
%   \usepackage{varwidth} %% 提供 varwidth 环境
%   \ctexset{
%     chapter/name = {第,回},
%     chapter/titleformat = \chaptertitleformat
%   }
%   \newcommand\chaptertitleformat[1]{%% 以标题内容为参数
%     \begin{varwidth}[t]{.7\linewidth}#1\end{varwidth}}
%   ......
%   \chapter{情中情因情感妹妹\\错里错以错劝哥哥}
%   \end{ctexexam}
%   上面的代码可以做出类似这样的章标题效果：
%   \begin{center}\Large\bfseries
%   第三十四回\quad
%   \begin{tabular}[t]{l}
%     情中情因情感妹妹\\
%     错里错以错劝哥哥
%   \end{tabular}
%   \end{center}
%
%   \opt{titleformat} 选项的默认设置见表~\ref{tab:titleformat-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \caption{\opt{titleformat} 选项的默认设置}
%   \label{tab:titleformat-default}
%   \begin{tabular}{lll}
%   \toprule
%   标题名 &amp; \opt{scheme = chinese} &amp; \opt{scheme = plain} \\
%   \midrule
%   part (article) &amp; |{}| &amp; |\huge\bfseries| \\
%   part (beamer) &amp; 同右 &amp; |\usebeamerfont{part title}| \\
%   part &amp; |{}| &amp; |\Huge\bfseries| \\
%   chapter &amp; |{}| &amp; |\Huge\bfseries| \\
%   section (beamer) &amp; 同右 &amp; |\usebeamerfont{section title}| \\
%   section &amp; 同右 &amp; |{}| \\
%   subsection (beamer) &amp; 同右 &amp; |\usebeamerfont{subsection title}| \\
%   subsection &amp; 同右 &amp; |{}| \\
%   subsubsection &amp; 同右 &amp; |{}| \\
%   paragraph &amp; 同右 &amp; |{}| \\
%   subparagraph &amp; 同右 &amp; |{}| \\
%   \bottomrule
%   \end{tabular}
% \end{table}
%
% \begin{function}[EXP,updated=2014-03-08]{.../aftername, .../aftername+}
%   \begin{syntax}
%   aftername = \Arg{代码}
%   aftername+= \Arg{代码}
%   \end{syntax}
%   \opt{aftername} 选项的参数 \meta{代码} 将被插入到章节编号与其后的标题内容之
%   间，用于控制格式变换。常用于控制章节编号与标题内容之间的距离，或者控制标题
%   是否另起一行。\opt{aftername+} 用于在已有的代码后附加内容。该选项的默认设置
%   见表~\ref{tab:aftername-default}。
% \end{function}
%
% \begin{function}[EXP,added=2015-06-19]{.../aftertitle, .../aftertitle+}
%   \begin{syntax}
%   aftertitle = \Arg{代码}
%   aftertitle+= \Arg{代码}
%   \end{syntax}
%   \opt{aftertitle} 选项的参数 \meta{代码} 将被插入到章节标题内容之后。
%   \opt{aftertitle+} 用于在已有的代码后附加内容。该选项的默认设置
%   见表~\ref{tab:aftertitle-default}。需注意，\opt{sub3section} 或
%   \opt{sub4section} 宏包选项（见 \ref{subs:options-heading}~节）会影响
%   \opt{aftertitle} 选项的默认值。
% \end{function}
%
% \begin{table}[htbp]
%   \setlength\leftskip{0pt plus 1 fil minus \marginparwidth}
%   \begin{minipage}[t]{.75\linewidth}
%     \small\centering
%     \caption{\opt{aftername} 选项的默认设置}
%     \label{tab:aftername-default}
%     \begin{tabular}{lll}
%     \toprule
%     标题名 &amp; \opt{scheme = chinese} &amp; \opt{scheme = plain} \\
%     \midrule
%     part (article) &amp; |\quad| &amp; |\par\nobreak| \\
%     part (beamer) &amp; 同右 &amp; |\vskip 1em \par| \\
%     part &amp; 同右 &amp; |\par\vskip 20pt| \\
%     chapter &amp; |\quad| &amp; |\par\nobreak\vskip 20pt| \\
%     section (beamer) &amp; 同右 &amp; |\vskip 1em \par| \\
%     section &amp; 同右 &amp; |\quad| \\
%     subsection (beamer) &amp; 同右 &amp; |\vskip 1em \par| \\
%     subsection &amp; 同右 &amp; |\quad| \\
%     subsubsection &amp; 同右 &amp; |\quad| \\
%     paragraph &amp; 同右 &amp; |\quad| \\
%     subparagraph &amp; 同右 &amp; |\quad| \\
%     \bottomrule
%     \end{tabular}
%   \end{minipage}\nobreak\quad
%   \begin{minipage}[t]{.42\linewidth}
%     \small\centering
%     \caption{\opt{aftertitle} 选项的默认设置}
%     \label{tab:aftertitle-default}
%     \begin{tabular}{p{\dimexpr .58\linewidth - 2\tabcolsep\relax}p{\dimexpr .4\linewidth - 2\tabcolsep\relax}}
%     \toprule
%     标题名 &amp; 默认值 \\
%     \midrule
%     part &amp; |\par| \\
%     chapter &amp; |\par| \\
%     section &amp; |\@@par| \\
%     subsection &amp; |\@@par| \\
%     subsubsection &amp; |\@@par| \\
%     paragraph &amp; |{}| \\
%     \qquad(sub3section) &amp; |\@@par| \\
%     \qquad(sub4section) &amp; 同上 \\
%     subparagraph &amp; |{}| \\
%     \qquad(sub4section) &amp; |\@@par| \\
%     \bottomrule
%     \end{tabular}
%   \end{minipage}
% \end{table}
%
% \begin{function}[EXP,added=2014-03-21]{part/pagestyle, chapter/pagestyle}
%   \begin{syntax}
%     pagestyle = \Arg{页面格式}
%   \end{syntax}
%   设置 \cls{book}/\cls{ctexbook} 或 \cls{report}/\cls{ctexrep} 文档类
%   中，\tn{part} 与 \tn{chapter} 标题所在页的页面格式（page style）。
%   该选项的默认设置见表~\ref{tab:pagestyle-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \caption{\opt{pagestyle} 选项的默认设置}
%   \label{tab:pagestyle-default}
%   \begin{tabular}{ll}
%   \toprule
%   标题名 &amp; 默认值 \\
%   \midrule
%   part (article) &amp; 无效 \\
%   part &amp; |plain| \\
%   chapter &amp; |plain| \\
%   \bottomrule
%   \end{tabular}
% \end{table}
%
% \subsection{间距、缩进相关}
% \label{subsec:sec-spacing}
%
% \begin{function}[EXP,added=2015-06-27]{section/runin, subsection/runin,
%   subsubsection/runin, paragraph/runin, subparagraph/runin}
%   \begin{syntax}
%   runin = \TF
%   \end{syntax}
%   \opt{runin} 选项只对 \tn{section} 级以下标题有意义，用于确定标题与随后的
%   正文是否排在同一段之上。该选项的默认设置见表~\ref{tab:runin-default}。
%
%   默认情况下，\tn{paragraph}、\tn{subparagraph} 两级标题是与后面正文排在同一
%   段的，\opt{runin} 选项为 \opt{true}；但使用 \opt{sub3section} 或
%   \opt{sub4section} 宏包选项（见 \ref{subs:options-heading}~节）后，将对
%   这两级标题设 \opt{runin} 选项为 \opt{false}，这两级标题会改为排在不同段。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \caption{\opt{runin} 选项的默认设置}
%   \label{tab:runin-default}
%   \begin{tabular}{ll}
%   \toprule
%   标题名 &amp; 默认值 \\
%   \midrule
%   part &amp; 无效 \\
%   chapter &amp; 无效 \\
%   section &amp; |false| \\
%   subsection &amp; |false| \\
%   subsubsection &amp; |false| \\
%   paragraph &amp; |true| \\
%   \qquad(sub3section) &amp; |false| \\
%   \qquad(sub4section) &amp; 同上 \\
%   subparagraph &amp; |true| \\
%   \qquad(sub4section) &amp; |false| \\
%   \bottomrule
%   \end{tabular}
% \end{table}
%
% \begin{function}[EXP,updated=2020-04-23]{.../hang}
%   \begin{syntax}
%   hang = \TF
%   \end{syntax}
%   \opt{hang} 选项用于设置是否对章节标题实施悬挂缩进（缩进的宽度为名字宽度
%   和 \opt{indent} 选项设置的宽度之和）。
%
%   注意，当 \opt{hang = true} 时，不恰当地设置选项 \opt{aftername} 的值，可能会引发
%   错误。这是因为当 \opt{hang = true} 时，\LaTeX{} 内部会构造一个 \tn{hbox} 而
%   进入受限水平模式（restricted horizontal mode）。若在 \opt{aftername} 中加入
%   包含 \tn{vskip} 等会导致从受限水平模式切出的垂直命令（vertical command）时，就会报错。
%   特别地，\opt{aftername} 的默认值也可能导致这种情形（见表~\ref{tab:aftername-default}）。
%   因此，当设置 \opt{hang = true} 时，用户必须恰当地设置选项 \opt{aftername} 的值。
%
%   本选项对 \cls{beamer}/\cls{ctexbeamer} 文档类无效。
%   对于 \tn{section} 级以下标题，若设置了 \opt{runin} 选项为 \opt{true}，
%   即标题与随后正文排在同一段，\opt{hang} 选项没有意义。
%   该选项的默认设置见表~\ref{tab:hang-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \begin{minipage}[t]{.5\linewidth}
%     \small\centering
%     \caption{\opt{hang} 选项的默认设置}
%     \label{tab:hang-default}
%     \begin{tabular}{ll}
%     \toprule
%     标题名 &amp; 默认值 \\
%     \midrule
%     part &amp; |false| \\
%     chapter &amp; |false| \\
%     section &amp; |true| \\
%     subsection &amp; |true| \\
%     subsubsection &amp; |true| \\
%     paragraph &amp; 无意义 \\
%     \qquad(sub3section) &amp; |true| \\
%     \qquad(sub4section) &amp; |true| \\
%     subparagraph &amp; 无意义 \\
%     \qquad(sub4section) &amp; |true| \\
%     \bottomrule
%     \end{tabular}
%   \end{minipage}^^A
%   \begin{minipage}[t]{.5\linewidth}
%     \small\centering
%     \caption{\opt{indent} 选项的默认设置}
%     \label{tab:indent-default}
%     \begin{tabular}{ll}
%     \toprule
%     标题名 &amp; 默认值 \\
%     \midrule
%     part &amp; |0pt| \\
%     chapter &amp; |0pt| \\
%     section &amp; |0pt| \\
%     subsection &amp; |0pt| \\
%     subsubsection &amp; |0pt| \\
%     paragraph &amp; |0pt| \\
%     subparagraph &amp; |\parindent| \\
%     \qquad(sub3section) &amp; |0pt| \\
%     \qquad(sub4section) &amp; 同上 \\
%     \bottomrule
%     \end{tabular}
%   \end{minipage}
% \end{table}
%
% \begin{function}[EXP,updated=2020-04-23]{.../indent}
%   \begin{syntax}
%   indent = \Arg{缩进间距}
%   \end{syntax}
%   \opt{indent} 选项用于设置章节标题本身的首行缩进。
%   该选项的默认设置见表~\ref{tab:indent-default}。
%
%   如果 \opt{indent} 的值是以 \texttt{em}、\texttt{ex} 或 \cs{ccwd} 为单位，
%   那么缩进间距的大小是相对于 \opt{format} 中指定的字号大小。
%   例如，设置 \tn{part} 标题缩进三个字、\tn{section} 标题缩进 \SI{20}{pt}：
%   \begin{ctexexam}
%   \ctexset{
%     part = {
%       format += \raggedright,
%       indent  = 3\ccwd,
%     },
%     section = {
%       format  = \Large\bfseries,
%       indent  = 20pt,
%     }
%   }
%   \part{首行缩进的标题}
%   \noindent 无缩进的正文。
%   \section{首行缩进的标题}
%   \noindent 无缩进的正文。
%   \end{ctexexam}
% \end{function}
%
% \begin{function}[EXP,updated=2016-05-10]{.../beforeskip}
%   \begin{syntax}
%   beforeskip = \Arg{弹性间距}
%   \end{syntax}
%   \opt{beforeskip} 选项用于设置章节标题前的垂直间距。
%   该选项的默认设置见表~\ref{tab:beforeskip-default}。
% \end{function}
%
% \begin{function}[EXP,updated=2015-06-27]{.../afterskip}
%   \begin{syntax}
%   afterskip = \Arg{弹性间距}
%   \end{syntax}
%   \opt{afterskip} 选项控制章节标题与后面下方之间的距离。
%
%   对于 \tn{section} 级以下标题，\opt{runin} 选项会影响 \opt{afterskip} 选项的意义：
%   若 \opt{runin} 为 \opt{true}，标题与随后正文排在同一段，\meta{弹性间距} 给出水平间距。
%   否则，正文另起一段，\meta{弹性间距} 给出的是垂直间距。
%
%   该选项的默认设置见表~\ref{tab:afterskip-default}。
%   注意 \opt{sub3section} 或 \opt{sub4section} 宏包选项（见
%   \ref{subs:options-heading}~节）会影响 \opt{aftertitle} 选项的默认值。
% \end{function}
%
% \begin{table}[htbp]
%   \setlength\leftskip{0pt plus 1 fil minus \marginparwidth}
%   \begin{minipage}[t]{.6\linewidth}
%     \small\centering
%     \caption{\opt{beforeskip} 选项的默认设置}
%     \label{tab:beforeskip-default}
%     \begin{tabular}{ll}
%     \toprule
%     标题名 &amp; 默认值 \\
%     \midrule
%     part (article) &amp; |4ex| \\
%     part (beamer) &amp; |0pt| \\
%     part &amp; |0pt plus 1fil| \\
%     chapter &amp; |50pt| \\
%     section (beamer) &amp; |0pt| \\
%     section &amp; |3.5ex plus 1ex minus .2ex| \\
%     subsection (beamer) &amp; |0pt| \\
%     subsection &amp; |3.25ex plus 1ex minus .2ex| \\
%     subsubsection &amp; |3.25ex plus 1ex minus .2ex| \\
%     paragraph &amp; |3.25ex plus 1ex minus .2ex| \\
%     subparagraph &amp; |3.25ex plus 1ex minus .2ex| \\
%     \bottomrule
%     \end{tabular}
%   \end{minipage}\nobreak\quad
%   \begin{minipage}[t]{.5\linewidth}
%     \small\centering
%     \caption{\opt{afterskip} 选项的默认设置}
%     \label{tab:afterskip-default}
%     \begin{tabular}{ll}
%     \toprule
%     标题名 &amp; 默认值 \\
%     \midrule
%     part (article) &amp; |3ex| \\
%     part (beamer) &amp; |0pt| \\
%     part &amp; |0pt plus 1fil| \\
%     chapter &amp; |40pt| \\
%     section (beamer) &amp; |0pt| \\
%     section &amp; |2.3ex plus .2ex| \\
%     subsection (beamer) &amp; |0pt| \\
%     subsection &amp; |1.5ex plus .2ex| \\
%     subsubsection &amp; |1.5ex plus .2ex| \\
%     paragraph &amp; |1em| \\
%     \qquad(sub3section) &amp; |1ex plus .2ex| \\
%     \qquad(sub4section) &amp; 同上 \\
%     subparagraph &amp; |1em| \\
%     \qquad(sub4section) &amp; |1ex plus .2ex| \\
%     \bottomrule
%     \end{tabular}
%   \end{minipage}
% \end{table}
%
% \begin{function}[EXP,added=2016-06-03]{.../fixskip}
%   \begin{syntax}
%   fixskip = \TFF
%   \end{syntax}
%   默认情况下，\cls{article}、\cls{book} 和 \cls{report} 类的标题与正文的距离
%   除了由 \opt{beforeskip} 和 \opt{afterskip} 选项设置的垂直间距外，还会有
%   一些多余的间距。\opt{fixskip} 选项用于抑制这些多余间距。该选项默认不开启。
% \end{function}
%
% \begin{function}[EXP,added=2016-09-19]{.../break, .../break+}
%   \begin{syntax}
%     break = \Arg{格式命令}
%     break+= \Arg{格式命令}
%   \end{syntax}
%   \opt{break} 选项用于控制章节标题与\emph{之前}正文的分隔关系。
%   一般用于设置是否在标题之前分页或者设置行间罚点。
%   \opt{break+} 用于在已有的格式命令后附加内容。
%
%   例如，若当前页剩余高度小于正文高度的一半时，则另起一页输出
%   \tn{section} 标题：
%   \begin{ctexexam}
%   \usepackage{needspace}
%   \ctexset{section/break = \Needspace{.5\textheight}}
%   \end{ctexexam}
%
%   该选项的默认设置见表~\ref{tab:break-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \caption{\opt{break} 选项的默认设置}
%   \label{tab:break-default}
%   \begin{tabular}{ll}
%   \toprule
%   标题名 &amp; 默认值 \\
%   \midrule
%   part (article) &amp; |{}| \\
%   part &amp; |\if@openright\cleardoublepage\else\clearpage\fi| \\
%   chapter &amp; 同上 \\
%   section &amp; |\addpenalty{\@secpenalty}| \\
%   subsection &amp; 同上 \\
%   subsubsection &amp; 同上 \\
%   paragraph &amp; 同上 \\
%   subparagraph &amp; 同上 \\
%   \bottomrule
%   \end{tabular}
% \end{table}
%
% \begin{function}[EXP,added=2015-06-27]{.../afterindent}
%   \begin{syntax}
%   afterindent = \TF
%   \end{syntax}
%   \opt{afterindent} 选项用于设置章节标题后首段的缩进。
%
%   \cls{book} 和 \cls{report} 类的 \tn{part} 标题被单独排在一页之上，
%   \opt{afterindent} 选项没有意义。
%   对于 \tn{section} 级以下标题，若设置了 \opt{runin} 选项为 \opt{true}，
%   即标题与随后正文排在同一段，\opt{afterindent} 选项也就没有了意义。
%
%   该选项的默认设置见表~\ref{tab:afterindent-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \caption{\opt{afterindent} 选项的默认设置}
%   \label{tab:afterindent-default}
%   \begin{tabular}{lll}
%   \toprule
%   标题名 &amp; \opt{scheme = chinese} &amp; \opt{scheme = plain} \\
%   \midrule
%   part (article) &amp; |true| &amp; |false| \\
%   part &amp; 无效 &amp; 无效 \\
%   chapter &amp; |true| &amp; |false| \\
%   section &amp; |true| &amp; |false| \\
%   subsection &amp; |true| &amp; |false| \\
%   subsubsection &amp; |true| &amp; |false| \\
%   paragraph &amp; |true| &amp; |false| \\
%   subparagraph &amp; |true| &amp; |false| \\
%   \bottomrule
%   \end{tabular}
% \end{table}
%
% \subsection{目录、附录相关}
% \label{subsec:sec-toc-appendix}
%
% \begin{function}[EXP,added=2020-05-06]{tocdepth}
%   \begin{syntax}
%     tocdepth = &lt;整数或章节名称&gt;
%   \end{syntax}
%   设置对章节标题编入目录的层次数。\opt{tocdepth} 的值可以是一个整数，也可以是
%   |part|, |chapter| 等名称。
%   层次数与名称的对应关系见表~\ref{tab:heading-level}。
%   章节层次的默认设置见表~\ref{tab:heading-level-default}。
% \end{function}
%
% \begin{function}[EXP,added=2016-10-25]{.../tocline}
%   \begin{syntax}
%     tocline = \Arg{格式定义}
%   \end{syntax}
%   \opt{tocline} 选项用于定义章节标题在目录文件（\file{.toc}）中的格式。
%   \meta{格式定义}有两个参数：参数 |#1| 是 |part|、|chapter| 等名字，
%   参数 |#2| 是标题内容。该选项的默认设置见表~\ref{tab:tocline-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \caption{\opt{tocline} 选项的默认设置}
%   \label{tab:tocline-default}
%   \begin{tabular}{ll}
%   \toprule
%   标题名 &amp; 默认值 \\
%   \midrule
%   part &amp; |\CTEXifname{\CTEXthepart\hspace{1em}}{}#2| \\
%   chapter (\opt{chinese})
%     &amp; |\CTEXifname{\protect\numberline{\CTEXthechapter\hspace{.3em}}}{}#2| \\
%   chapter (\opt{plain})
%     &amp; |\CTEXnumberline{#1}#2| \\
%   section &amp; |\CTEXnumberline{#1}#2| \\
%   subsection &amp; 同上 \\
%   subsubsection &amp; 同上 \\
%   paragraph &amp; 同上 \\
%   subparagraph &amp; 同上 \\
%   \bottomrule
%   \end{tabular}
%
%   \medskip
%   \raggedright
%   这里 \tn{CTEXnumberline} 的意义是，若标题 |#1| 没有名字，则不输出
%   |\numberline{\CTEXthe#1}| 等编号：
%   \begin{verbatim}
%     \CTEXifname{\protect\numberline{\csname CTEXthe#1\endcsname}}{}
%   \end{verbatim}
%   其中，\tn{CTEXifname} 的定义见 \ref{subsec:sec-commands}~小节。
% \end{table}
%
% \begin{function}[EXP,added=2016-10-01]{chapter/lofskip, chapter/lotskip}
%   \begin{syntax}
%   lofskip = \Arg{弹性间距}
%   lotskip = \Arg{弹性间距}
%   \end{syntax}
%   \opt{lofskip} 选项控制插图目录（\file{.lof}）中，章之间的插图标题的距离。
%   同样，\opt{lotskip} 选项控制表格目录（\file{.lot}）中，章之间的表格标题
%   的距离。
%
%   目前，这两个选项只在 \opt{chapter} 标题下有定义。
%   它们的默认值，在 \opt{scheme} 选项的不同取值下都为 \SI{10}{pt}。
% \end{function}
%
% \begin{function}[EXP,added=2015-06-21]{appendix/numbering}
%   \begin{syntax}
%     numbering = \TTF
%   \end{syntax}
%   控制是否对附录章（对应 \cls{book} 与 \cls{report}）或附录节
%   （对应 \cls{article}）进行编号，用法与普通章节对应的 \opt{numbering}
%   选项相同。该选项默认值为 \opt{true}。
% \end{function}
%
% \begin{function}[EXP,updated=2014-03-08]{appendix/name}
%   \begin{syntax}
%     name = \{&lt;前名字&gt;,&lt;后名字&gt;\}
%     name = \Arg{前名字}
%   \end{syntax}
%   设置附录章（对应 \cls{book} 与 \cls{report}）或附录节（对应 \cls{article}）
%   的名字，用法与普通章节对应的 \opt{name} 选项相同。
%
%   注意该选项与 \opt{appendixname} 选项（\ref{subs:capname}~节）在意义上有
%   些重叠，但不完全相同。\opt{appendixname} 选项只用来重定义
%   \tn{appendixname}，而不管 \tn{appendixname} 如何使用；该选项则决定在章节
%   标题中输出的名字，可以调用 \tn{appendixname} 设置。
%
%   该选项的默认设置见表~\ref{tab:appendix-name-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \caption{\opt{appendix/name} 选项的默认设置}
%   \label{tab:appendix-name-default}
%   \begin{tabular}{llllll}
%   \toprule
%   文档类 &amp; 影响命令 &amp; \opt{scheme = chinese} &amp; 实际定义
%     &amp; \opt{scheme = plain} &amp; 实际定义 \\
%   \midrule
%   \cls{article} &amp; \tn{section} &amp; |{}| &amp; &amp; |{}| &amp; \\
%   \cls{book}, \cls{report}
%       &amp; \tn{chapter} &amp; |\appendixname\space| &amp; \verb*|附录 |
%       &amp; |\appendixname\space| &amp; \verb*|Appendix | \\
%   \bottomrule
%   \end{tabular}
% \end{table}
%
% \begin{function}[EXP]{appendix/number}
%   \begin{syntax}
%     number = \Arg{数字输出命令}
%   \end{syntax}
%   设置附录章（对 \cls{book} 与 \cls{report}）或附录节（对 \cls{article}）
%   编号的数字输出格式，用法与普通章节对应的 \opt{number} 选项相同。
%
%   \opt{appendix/number} 选项同时也会控制附录章节计数器的交叉引用。
%   与普通章节的 \opt{number} 选项类似，同样需要注意，该选项不会影响计数器本身
%   的输出，即不影响 \tn{thesection} 或 \tn{thechapter} 的定义。
%
%   该选项的默认设置见表~\ref{tab:appendix-number-default}。
% \end{function}
%
% \begin{table}[htbp]
%   \small\centering
%   \caption{\opt{appendix/number} 选项的默认设置}
%   \label{tab:appendix-number-default}
%   \begin{tabular}{llllll}
%   \toprule
%   文档类 &amp; 影响命令 &amp; 默认值 \\
%   \midrule
%   \cls{article} &amp; \tn{section} &amp; |\Alph{section}| \\
%   \cls{book}, \cls{report} &amp; \tn{chapter} &amp; |\Alph{chapter}| \\
%   \bottomrule
%   \end{tabular}
% \end{table}
%
% \subsection{辅助命令}
% \label{subsec:sec-commands}
%
% \CTeX{} 宏集还提供了一些辅助命令（宏），用于存储章节标题格式，或进行一些条件判断。
%
% \begin{function}{\CTEXthepart, \CTEXthechapter, \CTEXthesection,
%   \CTEXthesubsection, \CTEXthesubsubsection, \CTEXtheparagraph,
%   \CTEXthesubparagraph}
%   以 |\CTEXthe| 开头的这组宏给出结合了 \opt{name} 与 \opt{number} 选项的章节
%   编号输出格式。例如在 \opt{scheme = chinese} 时，默认章编号输出格式就是
%   \tn{CTEXthechapter}，形如“第一章”。
%
%   这组宏在 \CTeX 文档类中将代替 \tn{thechapter} 等宏的作用，在章节中引用本章
%   节的完整编号。例如用于帮助定义自定义的目录格式、页眉格式等。
% \end{function}
%
% \begin{function}[added=2016-09-18]{\CTEXifname}
%   \begin{syntax}
%     \tn{CTEXifname} \Arg{有名字时的内容} \Arg{无名字时的内容}
%   \end{syntax}
%   \tn{CTEXifname} 会根据当前章节有无名字展开得到不同内容（通常是格式命令）。
%   由于章节名字总是与编号一起出现，章节有无名字通常也表达为“章节是否编号”。
%   在 \LaTeX{} 中，后者取决于以下几个方面：章节深度是否不大于计数器
%   |secnumdepth| 的值，章节标题是否使用不带星号的命令。在 \CTeX{} 宏集中，
%   后者还取决于 \opt{.../numbering} 是否为 \opt{true}。
%
%   \tn{CTEXifname} 可用于 \opt{format}, \opt{titleformat}, \opt{aftertitle},
%   \opt{afterskip}, \opt{indent} 这五个选项和 \tn{chapter} 标题
%   \opt{beforeskip} 选项的格式设置之中。也可用于帮助定义自定义的目录格式、
%   页眉格式等。
%
%   例如，设置章的标题有名字时左对齐，无名字时居中对齐，并且在标题后画一条横线。
%   \begin{ctexexam}
%   \ctexset{
%     chapter/format     = \CTEXifname{\raggedright}{\centering},
%     chapter/aftertitle = \par\CTEXifname{}{\hrule},
%   }
%   \end{ctexexam}
% \end{function}
%
% \subsection{示例}
%
% 我们最后举一个稍微复杂的例子，来看看上述选项的综合应用。
%
% \begin{ctexexam}[labelref=exam:miscopt]
%   \ctexset {
%     chapter = {
%       beforeskip = 0pt,
%       fixskip    = true,
%       format     = \Huge\bfseries,
%       nameformat = \rule{\linewidth}{1bp}\par\bigskip\hfill\chapternamebox,
%       number     = \arabic{chapter},
%       aftername  = \par\medskip,
%       aftertitle = \par\bigskip\nointerlineskip\rule{\linewidth}{2bp}\par
%     }
%   }
%   \newcommand\chapternamebox[1]{%
%     \parbox{\ccwd}{\linespread{1}\selectfont\centering #1}}
%   ......
%   \chapter{熟悉 \LaTeX}
% \end{ctexexam}
% 本例的设置效果大致如下：
% \begin{center}
% \begin{minipage}{.75\linewidth}\Large\bfseries
% \hrule height .5bp \relax
% \medskip
% \hfill\parbox{\ccwd}{\linespread{1}\selectfont\centering 第 1 章}
% \par\smallskip
% \noindent 熟悉 \LaTeX
% \medskip\hrule height 1bp \relax
% \end{minipage}
% \end{center}
%
% \section{实用命令}
% \label{sec:useful-commands}
% \subsection{字号与间距}
%
% \begin{function}[updated = 2014-03-08, label = ]{\zihao}
%   \begin{syntax}
%     \tn{zihao} \Arg{字号}
%   \end{syntax}
%   用于调整字号大小。其中 \meta{字号} 的有效值共有 16 个，如表 \ref{tab:zihao}
%   所示。使用 \tn{zihao} 命令调整字体大小时，西文字号大小会始终和中文字号保持一致。
% \end{function}
%
% \begin{table}[!htbp]
% \centering
% \def\ZH#1{\zihaopt{#1} &amp; \zihao{#1}}
% \tabcolsep=1em
% \caption{中文字号}\label{tab:zihao}
% \begin{tabular}{&gt;{\ttfamily}S[mode=text,detect-family,table-format=-1]
%                             S[table-format=2.1]S[table-format=2.5]l}
% \toprule
% {\meta{字号}} &amp; {大小(bp)} &amp; {大小(pt)} &amp; 意义 \\
% \midrule
%  0   &amp; 42   &amp; \ZH{0}    初号    \\
% {−0} &amp; 36   &amp; \ZH{-0}   小初号  \\
%  1   &amp; 26   &amp; \ZH{1}    一号    \\
% -1   &amp; 24   &amp; \ZH{-1}   小一号  \\
%  2   &amp; 22   &amp; \ZH{2}    二号    \\
% -2   &amp; 18   &amp; \ZH{-2}   小二号  \\
%  3   &amp; 16   &amp; \ZH{3}    三号    \\
% -3   &amp; 15   &amp; \ZH{-3}   小三号  \\
%  4   &amp; 14   &amp; \ZH{4}    四号    \\
% -4   &amp; 12   &amp; \ZH{-4}   小四号  \\
%  5   &amp; 10.5 &amp; \ZH{5}    五号    \\
% -5   &amp;  9   &amp; \ZH{-5}   小五号  \\
%  6   &amp;  7.5 &amp; \ZH{6}    六号    \\
% -6   &amp;  6.5 &amp; \ZH{-6}   小六号  \\
%  7   &amp;  5.5 &amp; \ZH{7}    七号    \\
%  8   &amp;  5   &amp; \ZH{8}    八号    \\
% \bottomrule
% \end{tabular}
% \end{table}
%
% \begin{function}[updated=2014-03-28]{\ziju}
%   \begin{syntax}
%     \tn{ziju} \Arg{中文字符宽度的倍数}
%   \end{syntax}
%   用于调整相邻汉字之间的间距，即（在正常中文行文中）前一个汉字的右边缘与后一个汉字
%   的左边缘之间的距离。其中参数可以是任意浮点数值；而中文字符宽度指的是实际汉字的
%   宽度，不包含当前字距。
%
%   这个命令会影响 \tn{ccwd} 的值，但不会影响英文字距。
% \end{function}
%
% \begin{function}[updated=2014-03-27]{\ccwd}
%   当前汉字的字宽保存在长度寄存器 \tn{ccwd} 之中。汉字字宽是相邻两个汉字中心
%   之间的距离，包含字距在内。因此修改字距会间接修改字宽。
% \end{function}
%
% \subsection{中文数字转换}
%
% \CTeX{} 宏集的中文数字转换功能实际上是调用 \pkg{zhnumber} 宏包来完成。下面只
% 介绍一些基本的用法，更高级的用法可以查阅 \pkg{zhnumber} 宏包的文档。
%
% \begin{function}[updated=2016-05-01]{\chinese}
%   \begin{syntax}
%     \tn{chinese} \Arg{counter}
%     \tn{pagenumbering} \{chinese\}
%   \end{syntax}
%   \tn{chinese} 命令与 \tn{roman} 等命令的用法类似，作用在一个 \LaTeX{}
%   计数器上，将计数器的值以中文数字的形式输出。
% \end{function}
%
% \begin{function}[added=2014-03-08]{\zhnumber}
%   \begin{syntax}
%     \tn{zhnumber} \Arg{number}
%   \end{syntax}
%   以中文格式输出数字。这里的数字可以是整数、小数和分数。
% \end{function}
%
% \begin{function}[added=2014-03-08]{\zhdigits}
%   \begin{syntax}
%     \tn{zhdigits} \Arg{number}
%   \end{syntax}
%   将阿拉伯数字转换为中文数字串。
% \end{function}
%
% \begin{function}{\CTEXnumber}
%   \begin{syntax}
%     \tn{CTEXnumber} "\"&lt;macro&gt; \Arg{number}
%   \end{syntax}
%   |\|&lt;macro&gt; 必须是一个 \TeX{} 宏，不需预先定义。\tn{CTEXnumber} 通过
%   \tn{zhnumber} 将 \meta{number} 转为中文数字，最后将结果存储在 |\|&lt;macro&gt;
%   里。对 |\|&lt;macro&gt; 的定义是局部的，将它展开一次就可以得到转换结果。
% \end{function}
%
% 一般来说，并不需要使用 \tn{CTEXnumber}，直接使用 \tn{zhnumber} 即可。但是，如果
% 在文档中需要多次使用同一个数字 \meta{number} 的中文形式，就可以先用
% \tn{CTEXnumber} 将结果保存起来备用，而不是每次使用时都用 \tn{zhnumber} 现场
% 转换一次。
%
% \begin{function}{\CTEXdigits}
%   \begin{syntax}
%     \tn{CTEXdigits} "\"&lt;macro&gt; \Arg{number}
%   \end{syntax}
%   \tn{CTEXdigits} 与 \tn{CTEXnumber} 类似，但其转换的结果是中文数字串，而不是
%   中文数字。
% \end{function}
%
% \subsection{杂项}
%
% \begin{function}{\CTeX}
% 用于显示 \CTeX 标志。
% \end{function}
%
% \section{\LuaLaTeX{} 下的中文支持方式}
% \label{sec:lualatex-chinese}
%
% 在 \LuaLaTeX{} 下，\CTeX{} 宏集依赖 \pkg{LuaTeX-ja} 宏包来完成中文支持。
% 该宏包是日本 \TeX{} 社区的北川弘典、前田一贵、八登崇之等人开发的，设计目的主要
% 是在 \LuaTeX{} 引擎下实现日本 p\TeX{} 引擎的（大部分）功能。它为了兼容 p\LaTeX
% 的使用习惯，对 \LaTeXe 的 \pkg{NFSS} 作了不少修改和扩充。这对于简体中文用户来说
% 不是必要的，因而 \CTeX{} 禁用了它在 \LaTeX{} 格式下的大部分设置，只保留了必要的
% 部分。同时修改了它的字体设置方式，使得相关命令与 \pkg{xeCJK} 宏包大致相同。
%
% 20150420 版以后的 \pkg{LuaTeX-ja} 宏包开始支持竖排，但 \CTeX{} 暂不支持竖排。
%
% \subsection{\LuaLaTeX{} 下替代字体的设置}
%
% \begin{function}[updated=2020-04-30]{AlternateFont}
%   \begin{syntax}
%     \tn{setCJKfamilyfont} \Arg{family} \Arg{base font name}
%     \  [
%     \    &lt;base font features&gt; ,
%     \    AlternateFont =
%     \      \{
%     \        \Arg{character range_1} \Arg{alternate font name_1} ,
%     \        \Arg{character range_2} \Arg{alternate font name_2} \Arg{alternate font features_2} ,
%     \        ......
%     \      \}
%     \  ]
%   \end{syntax}
%   在设置字体族 \meta{family} 的时候，同时设置该字体族在字符范围
%   \meta{character range_n} 内，对应字形的替代字体。
% \end{function}
%
% \begin{function}[added=2014-04-14]{CharRange}
%   \begin{syntax}
%     \tn{setCJKfamilyfont} \Arg{family} \Arg{alternate font name}
%     \  [
%     \    CharRange = \Arg{character range} ,
%     \    &lt;alternate font features&gt;
%     \  ]
%   \end{syntax}
%   只设置字体族 \meta{family} 在字符范围 \meta{character range} 内，对应字形的
%   替代字体。
% \end{function}
%
% 一个 \tn{setCJKfamilyfont} 里只能使用一次 \opt{CharRange} 或者
% \opt{AlternateFont}，但可以将它们分开重叠使用。例如下面的方式是有效的。
%
% \begin{ctexexam}
%   \setCJKmainfont[AlternateFont={...}{...}, ...]{...}
%   \setCJKmainfont[CharRange={"4E00-&gt;"67FF,-2}, ...]{...}
%   \setCJKmainfont[CharRange={"6800-&gt;"9FFF}, ...]{...}
% \end{ctexexam}
%
% \begin{function}[EXP,added=2020-04-30]{declarecharrange}
%   \begin{syntax}
%     \tn{ctexset}
%     \  \{
%     \    declarecharrange =
%     \      \{
%     \        \Arg{name_1} \Arg{character range_1} ,
%     \        \Arg{name_2} \Arg{character range_2} ,
%     \        ...
%     \      \}
%     \  \}
%   \end{syntax}
%   预先声明字符范围。声明字符范围 \meta{name} 之后，它的名字 \meta{name} 可以
%   用在 \opt{AlternateFont} 和 \opt{CharRange} 选项的 \meta{character range}
%   之中，表示对应的字符范围。
% \end{function}
%
% 在声明字符范围 \meta{name} 的同时，还为 \tn{setCJKmainfont} 等字体设置命令定义
% 了选项 \meta{name}，用于设置对应字符的替代字体：
% \begin{syntax}
%   \meta{name} = \Arg{alternate font name}
%   \meta{name} = \Arg{alternate font name} \Arg{alternate font features}
% \end{syntax}
% \meta{name} 选项可以与 \opt{AlternateFont} 共同使用，但不能与 \opt{CharRange}
% 一起使用。如果没有给 \meta{name} 设置值，则等价于设置 \opt{CharRange=\meta{name}}，
% 即只设置 \meta{name} 对应的字符范围的替代字体。
%
% \begin{function}[EXP,added=2014-04-15]{clearalternatefont,resetalternatefont}
%   \begin{syntax}
%     \tn{ctexset}
%     \  \{
%     \    clearalternatefont = \Arg{family_1, family_2, ...} ,
%     \    resetalternatefont = \Arg{family_1, family_2, ...} ,
%     \    clearalternatefont ,
%     \    resetalternatefont
%     \  \}
%   \end{syntax}
%   清除与重置 CJK 字体族 \meta{family} 的替换字体设置。如果没有给定值，则作用于
%   当前 CJK 字体族。清除与重置操作总是全局的。
% \end{function}
%
% \section{\CTeX{} 宏集的配置文件}
%
% \CTeX{} 宏集提供了不同的配置文件，可以通过修改配置文件来改变 \CTeX{} 宏集的
% 默认行为。
%
% 在多数情况下，并不需要修改配置文件，\CTeX{} 宏集的默认设置已经能满足大多数用
% 户的需要。不恰当地修改 \CTeX{} 宏集的默认行为也可能导致同一文件在别处无法正
% 常编译或排版效果完全不同，因此修改应该慎重。
%
% 但在一些情况下，直接修改配置文件仍是必要的，例如：
% \begin{itemize}
% \item 系统没有安装默认设置的字体文件，无法编译。
% \item 需要经常编译来自其他系统的中文 \TeX{} 文件，但对方的操作系统或默认设置
% 与本机不同。
% \end{itemize}
%
% 与 \CTeX{} 宏集的源代码一样，配置文件采用 \LaTeXiii{} 的语法编写。
%
% \CTeX{} 宏集的配置文件随宏包其他文件一起安装在 \TeX{} 系统 TDS 目录树中，文
% 件后缀是 \file{.cfg}。为了避免本地配置文件内容因 \CTeX{} 宏集的更新而丢失，
% 不要直接修改系统 TDS 目录树中的配置文件，而应该将系统自带的配置文件复制到本
% 地的或用户私有的 TDS 目录树中修改，并运行 \bashcmd{texhash} 命令刷新文件名数据库。
%
% 例如对于 \TeX{} Live，系统自带的配置文件就在 \TeX{} Live 安装目录下的
% \path{texmf-dist/tex/latex/ctex/config/} 子目录下，可以修改它的副本，保存在
% 本地 TDS 树的 \path{texmf-local/tex/latex/ctex/} 目录下，或者用户 TDS 树的
% \path{~/texmf/tex/latex/ctex/} 目录下，作为本地/用户专有的
% 配置文件。复制配置文件后需要运行 |texhash| 命令使本地配置文件生效。
%
% \MiKTeX{} 的配置文件也保存在类似的目录结构中，\MiKTeX{} 管理的
% 几个 TDS 根目录可以在 \MiKTeX{} Options 设置项中查看到，这里不再赘述。
%
% 除了修改本地 \TeX{} 系统中的配置文件，对于特定文档，也可以将修改过的配置文件
% 保存在文档的工作目录下。此时配置文件就只对工作目录下的所有文档生效。
%
% \subsection{修改宏包默认选项}
%
% 配置文件 \file{ctexopts.cfg} 可以用来修改宏包的默认选项。随系统安装的配置文
% 件除了文件信息声明外没有实际的内容，但在注释中给出了一个简单的示例，只要取消
% 注释就可以生效。
%
% \begin{ctexexam}
%   % 系统自带 ctexopts.cfg 注释中的示例语句，固定默认字体集为 windows。
%   % 该设置可以用在安装了 Windows 字体的非 Windows 系统中。
%   \ctex_set:nn { option } { fontset = windows }
% \end{ctexexam}
% 如上例所示，宏包选项通常使用 \LaTeXiii{} 的 \cs{ctex_set:nn} 命令完成键值设置，
% 第一个参数是固定的子模块 |option|，第二个参数中是用户定义的新的默认宏包选项。
%
% \file{ctexopts.cfg} 中的设置将在 \CTeX{} 宏集的开始处，定义过宏包选项之后，
% \tn{ProcessKeysOptions} 命令之前生效。最好只使用此配置文件修改宏包默认选项。
%
% \subsection{宏包载入后的配置}
%
% 配置文件 \file{ctex.cfg} 将在宏包的末尾被载入生效。可以用它完成任意的设置，
% 或是覆盖已有的定义。随系统安装的配置文件除版本信息外没有实际内容，注意配置文
% 件中也使用 \LaTeXiii{} 语法。
%
% \begin{ctexexam}
%   % 简单的 ctex.cfg 内容示例。
%   % 修改默认的页面格式设置。
%   \pagestyle{plain}
% \end{ctexexam}
%
% \begin{ctexexam}
%   % 略复杂的 ctex.cfg 内容示例：禁止段末孤字成行。
%   % 在使用 XeTeX 编译时，打开 xeCJK 的 CheckSingle 选项。
%   \sys_if_engine_xetex:T
%     {
%       \xeCJKsetup { CheckSingle }
%     }
%   % 在使用 LuaTeX 编译时，设置 LuaTeX-ja 的 jcharwidowpenalty 参数。
%   \sys_if_engine_luatex:T
%     {
%       \ltjsetparameter { jcharwidowpenalty = 10000 }
%     }
% \end{ctexexam}
%
% \subsection{配置标题中文翻译}
%
% 由于 \CTeX{} 宏集需要同时支持 GBK 和 UTF-8 两种编码，因此对标题的中文翻译写
% 在两个配置文件当中：\file{ctex-name-gbk.cfg} 和 \file{ctex-name-utf8.cfg}。
% 两个文件的设置相同，只是编码不同。
%
% 为了同一文档在不同电脑上编译效果的一致性，通常不建议修改默认的中文翻译。
%
% \subsection{自定义字体集}
%
% \ref{subs:options-CJK-font}~节介绍的用于 |fontset| 选项的自定义字库文件，
% 类似于 \CTeX{} 宏集的配置文件，也应该与其他本地配置文件一起保存在本地
% \texttt{TDS} 目录树下，并可以配合 \file{ctexopts.cfg} 等配置文件使用。
%
% \section{对旧版本的兼容性}
%
% \subsection{\CTeX\ 0.8a 及以前的版本}
%
% 在 ctex-kit 项目成立之前，\CTeX 宏包的最后一个版本是 \CTeX\
% 0.8a（2007/05/06）。
%
% 第 2 版未考虑对这些很早版本的兼容性。
%
% \subsection{\CTeX\ 0.9--\CTeX\ 1.0d}
%
% 在 2009 年在 ctex-kit 项目成立后，新增了 \XeTeX{} 引擎的支持，并增加了不少控
% 制字体的命令和选项。
%
% 这里主要介绍新版本 \CTeX 宏包相对 1.02d 版本（2014/06/09）的兼容性。
%
% 第 2 版的 \CTeX 宏包已尽力保证对 1.0x 版本的兼容性，原有为 1.0x 编写的代码，
% 在第 2 版的 \CTeX 宏包下保证仍能编译，并且在大多数情况下保持编译效果不变。
%
% \CTeX 宏包在 0.8a 以前的版本支持以 \pkg{CCT} 作为底层中文支持方式，从 0.9 版
% 之后即不再推荐使用，只保留向后兼容。在 \CTeX 宏包第 2 版中则完全不再支持
% \pkg{CCT}。
%
% 下面这些是在旧版本 \CTeX 宏包中存在，而在新版本中已不建议使用的选项和命令，
% 在未来版本中可能会删去它们的支持。
%
% 在多数情况下它们的功能仍将保留，但也有部分选项命令功能已失效。
%
% \begin{function}{cs4size, c5size}
%   分别相当于 |zihao=-4| 和 |zihao=5|，过时选项。
% \end{function}
%
% \begin{function}{CCT, CCTfont}
% 相关选项已删除。
% \end{function}
%
% \begin{function}{indent, noindent}
% \opt{indent} 和 \opt{noindent} 什么也不做，过时选项。
%
% 在中文版式下，\pkg{ctex} 宏包的相关功能在与标准文档类及其衍生文档类联用时
% 默认打开。\CTeX{} 文档类的相关功能由章节标题的 \opt{afterindent} 选项的值
% 来确定。
% \end{function}
%
% \begin{function}[label = ]{zhmap, nozhmap}
% \opt{zhmap} 宏包选项增加了参数，扩充了功能，除了支持真假值参数外，还支持选择
% \pkg{zhmCJK} 作为底层中文处理宏包。（\ref{subs:options-CJK-font}~节）
%
% \opt{nozhmap} 选项相当于 |zhmap=false|。过时选项。
% \end{function}
%
% \begin{function}{winfonts, adobefonts, nofonts}
% 宏包选项 \opt{winfonts} 相当于 |fontset=windows|，\opt{adobefonts} 相当于
% |fontset=adobe|，\opt{nofonts} 相当于 |fontset=none|。这几个选项是过时选项，
% 对于新文档，应使用 \opt{fontset} 选项设置不同字体集。
%
% 另外，第 2 版 \CTeX 宏包的默认字体不再是 Windows 系统字体，而是根据检测到的
% 操作系统选择使用 Windows、Mac 的系统字体还是 Fandol 字体
% （\ref{subs:options-CJK-font}~节）。
% \end{function}
%
% \begin{function}[label = ]{punct, nopunct}
% 旧版本中宏包 \opt{punct} 选项没有参数，现在可以用参数设定标点风格
% （\ref{subs:options-type-style}~节）。原有无参形式的 \opt{punct} 选项相当
% 于 |punct=quanjiao|。
%
% 旧版宏包中 \opt{nopunct} 选项的效果大致相当于 |punct=plain|。过时选项，不推荐使用。
% \end{function}
%
% \begin{function}{cap, nocap}
% 原有的 \opt{cap} 和 \opt{nocap} 选项由新的 \opt{scheme} 选项代替。
% （\ref{subs:options-type-style}~节）
%
% \opt{cap} 选项相当于 |scheme = chinese|，\opt{nocap} 选项相当
% 于 |scheme = plain|。它们均已过时，仅因兼容性而保留。
% \end{function}
%
% \begin{function}[label = ]{space, nospace}
% 新版本宏包 \opt{space} 选项增加真假值参数。
% （\ref{subs:options-type-style}~节）
%
% \opt{nospace} 选项相当于 |space=false|，成为过时选项。
% \end{function}
%
% \begin{function}{fancyhdr}
% 新版本宏包中总是自动处理对 \pkg{fancyhdr} 宏包的兼容性，而由用户自己使用
% \tn{usepackage} 载入 \pkg{fancyhdr} 宏包。
%
% \opt{fancyhdr} 选项过时，因兼容性保留，功能是载入 \pkg{fancyhdr} 宏包。
% \end{function}
%
% \begin{function}{hyperref}
% 新版本宏包中总是自动处理对 \pkg{hyperref} 宏包的兼容性，而由用户自己使用
% \tn{usepackage} 载入 \pkg{hyperref} 宏包。
%
% \opt{hyperref} 选项过时，因兼容性保留，功能是在导言区末尾载入 \pkg{hyperref}
% 宏包。
% \end{function}
%
% \begin{function}{fntef}
% 旧版本的 \opt{fntef} 选项用于统一 \pkg{CCTfntef} 与 \pkg{CJKfntef} 的界面，
% 新版本 \CTeX{} 宏集不再支持 \pkg{CCT}，也不再自动载入 \pkg{CJKfntef} 或
% \pkg{xeCJKfntef} 宏包，而仅在其末尾做适当格式调整。
%
% \opt{fntef} 选项过时，因兼容性保留，功能是根据引擎载入 \pkg{CJKfntef}
% (\pdfTeX{}) 或 \pkg{xeCJKfntef} (\XeTeX{}) 宏包。
% \end{function}
%
% \begin{function}{\CTEXunderdot, \CTEXunderline, \CTEXunderdblline,
%   \CTEXunderwave, \CTEXsout, \CTEXxout, CTEXfilltwosides}
% 在调用 \opt{fntef} 宏包选项的同时，旧版本 \CTeX{} 宏包由于需要支持 \pkg{CCT}
% 系统，会将以 |\CJK| 开头的 \tn{CJKunderline} 等宏换名为以 |\CTEX| 开头的
% \tn{CTEXunderline} 等宏。此功能在新版本的 \CTeX{} 宏集中已失去意义。此外，
% 在 \pdfTeX{} 引擎下，用于设置格式的 \tn{CJKunderdotbasesep} 等宏也被更名为
% \tn{CTEXunderdotbasesep} 等宏。
%
% 在新版本中，上述由 \opt{fntef} 衍生的相关命令和环境均被移除。
% \end{function}
%
% \begin{function}{\CTEXsetfont}
% 更新当前的中文字体信息，包括当前字距（\tn{ccwd}）和段首缩进（\tn{parindent}）。
% 一般来说，用户无需使用这个命令。
% \end{function}
%
% \begin{function}{\CTEXindent}
% 更新 \tn{ccwd} 宽度后设置 |\parindent=2\ccwd|。过时命令。
% \end{function}
%
% \begin{function}{\CTEXnoindent}
% 设置 |\parindent=0pt|。过时命令。
% \end{function}
%
% \begin{function}{\CTEXsetup}
% \begin{syntax}
%   \tn{CTEXsetup}\oarg{选项}\Arg{标题}
% \end{syntax}
% 相当于设置了
% \texttt{\tn{ctexset}\{ \meta{标题} = \Arg{选项} \}}。
% 过时命令。
% \end{function}
%
% \begin{function}{\CTEXoptions}
% \begin{syntax}
%   \tn{CTEXoptions}\oarg{选项}
% \end{syntax}
% 相当于设置了
% \texttt{\tn{ctexset}\Arg{选项}}。
% 过时命令。
% \end{function}
%
% \begin{function}{\Chinese}
% \begin{syntax}
%   \tn{Chinese}\Arg{counter}
% \end{syntax}
% 新版宏集中 \tn{chinese} 统一了旧版本中 \tn{chinese} 和 \tn{Chinese} 的功能。因此，
% 该命令已过时。
% \end{function}
%
% \begin{function}{captiondelimiter}
% 原为 \tn{CTEXoptions} 命令的选项，用于控制 \tn{caption} 编号后面的标点。此选
% 项已过时，并在新版本的 \CTeX 宏包中失效。
%
% 可以使用 \pkg{caption} 宏包的 \opt{labelsep} 选项来完成同样的功能。
% \begin{ctexexam}
%   % 代替 \CTEXoptions[captiondelimiter={:}]
%   \usepackage{caption}
%   \captionsetup{labelsep=colon}
% \end{ctexexam}
% \end{function}
%
% \subsection{\CTeX\ 1.02c 以后的 SVN 开发版}
%
% \CTeX 宏包在 1.02c 版本（2011/03/11）之后在 Google code 上的 SVN 开发版本，
% 内部版本号一直升到 1.11 版，但从未正式发布。SVN 开发版在 1.02c 版本的基础上
% 新增的功能在第 2 版中大多继承了过来，但新增的命令与选项都不再保持兼容。
%
% \CTeX 宏包第 2 版不保证对未发布的 SVN 开发版兼容。
%
% \subsection{\CTeX\ 2.2 之前的版本}
%
% \begin{function}{part/beforeskip, chapter/beforeskip, section/beforeskip,
%   subsection/beforeskip, subsubsection/beforeskip, paragraph/beforeskip,
%   subparagraph/beforeskip}
%   在 \CTeX\ 2.2 之前的版本中，\opt{beforeskip} 选项的符号还用于确定章节标题后
%   首段的缩进。当 \opt{beforeskip} 是负值时，章节标题后的第一段按英文文档的排版
%   习惯，没有首行缩进，否则保留首行缩进。
%
%   这一特性在 2.2 版和后续版本中不再保留，相应的功能通过新的 \opt{afterindent}
%   选项来设置。如果原先设置 \opt{beforeskip} 为负值，在新版本中需要改为正值，
%   并设置相应的 \opt{afterindent} 选项为 \opt{false}。
% \end{function}
%
% \begin{function}{section/afterskip, subsection/afterskip,
%   subsubsection/afterskip, paragraph/afterskip, subparagraph/afterskip}
%   在 \CTeX\ 2.2 之前的版本中，对于 \tn{section} 级以下标题，\opt{afterskip}
%   选项的符号用于确定标题与随后正文是否排在同一段。
%   如果是正值，则正文另起一段，否则标题与随后正文排在同一段，
%   \opt{afterskip} 的绝对值给出水平间距。
%
%   这一特性在 2.2 版和后续版本中不再保留，相应的功能通过新的 \opt{runin}
%   选项来设置。如果原先设置 \opt{afterskip} 为负值，在新版本中需要改为正值，
%   并设置相应的 \opt{runin} 选项为 \opt{true}。
% \end{function}
%
% \subsection{\CTeX\ 2.4.1 和 2.4.2}
%
% \begin{function}{part/fixbeforeskip, chapter/fixbeforeskip}
%   这两个选项已经被删除，相应功能由新的选项 \opt{fixskip} 提供。
% \end{function}
%
% \subsection{\CTeX\ 2.5 之前的版本}
%
% \CTeX\ 2.5 有一些比较大的变动。
%
% \begin{function}[label =]{UTF8, GBK}
%   (pdf)\LaTeX{} 格式下，文档编码初始值统一设置成 UTF-8。因此，仍旧使用 GBK
%   编码的文档，需要在文档类或宏包选项中显式指定 \opt{GBK}。
% \end{function}
%
% \begin{function}[label =]{\CTEXunderdot, \CTEXunderline, \CTEXunderdblline,
%   \CTEXunderwave, \CTEXsout, \CTEXxout, CTEXfilltwosides}
%   不再默认载入 \pkg{CJKfntef} 或 \pkg{xeCJKfntef} 宏包，同步移除有关命令
%   和环境。若需使用相关宏包，建议用户使用 \tn{usepackage} 命令主动载入。
% \end{function}
%
% \begin{function}[label =]{fntef}
%   作为兼容性保留，会视编译引擎载入相应宏包。
% \end{function}
%
% \begin{function}{windows}
%   不再支持 Windows XP 系统，默认要求 Windows 系统有微软雅黑字体。
%   建议 Windows XP 系统的用户及时更新操作系统。若一定要在 Windows XP 中使用，
%   请使用 2.5 以前的版本。
% \end{function}
%
% \begin{function}{windowsold, windowsnew}
%   过时字库选项，作为兼容性保留，功能是载入 \opt{windows} 字库。
% \end{function}
%
% \begin{function}{ubuntu}
%   改用思源（Noto CJK）和文鼎字库。该字库不再支持 \pdfLaTeX 编译。
% \end{function}
%
% \begin{function}[label =]{AlternateFont}
%   不再支持将替代字体的可选项放在字体名之前的方括号中，
%   新的语法是将可选项放在字体名之后的花括号之内。
% \end{function}
%
% 除了以上列出的选项以外，当用户使用 \CTeX{} 系列文档类，且使用 \LaTeX 或
% \upLaTeX 编译时，若用户没有在文档类选项中显式指定 |dvips|/|dvipdfmx|/|dvisvgm|
% 等驱动选项，则文档类指定默认驱动为 \dvipdfmx。
%
% \section{宏集依赖情况与手工安装方法}
% \label{sec:dep-ins}
%
% 本节介绍 \CTeX{} 宏集的依赖情况，并介绍手工编译安装的具体方法。
% 通常用户只需参照第 \ref{subsec:easy-ins}~节介绍的方法，使用发行版自带的包管理器安装
% 本宏集。
%
% \CTeX{} 宏集有两个源文件：\file{ctex.dtx}、\file{ctexpunct.spa}。
% 使用不同的编译方式时，\CTeX{} 依赖的宏包略有不同。在手工安装 \CTeX{} 宏集之前，请确保
% 你的 \TeX{} 发行版中已经正确安装了这些宏包。\CTeX{} 依赖宏包的详情叙述如下：
%
% \begin{itemize}
%   \item \pkg{expl3}、\pkg{xparse} 和 \pkg{l3keys2e} 宏包。它们属于 \pkg{l3kernel}
%   和 \pkg{l3packages} 宏集。
%   \item \pkg{indentfirst} 宏包，属于 \pkg{tools} 宏集。
%   \item \pkg{zhnumber} 宏包。
%   \item[\ding{229}] 以上是各种编译方式都必需的依赖项。
%   \item \pkg{CJK} 宏集。
%   \item \pkg{CJKpunct} 宏包。
%   \item \pkg{xCJK2uni} 宏包。
%   \item \pkg{zhmetrics} 宏包。
%   \item \pkg{zhmCJK} 宏包，它还依赖
%   \begin{itemize}
%     \item \pkg{iftex} 宏包。
%     \item \pkg{ltxcmds} 宏包。
%     \item \pkg{kvoptions} 宏包。
%     \item \pkg{kvsetkeys} 宏包。
%     \item \pkg{keyval} 宏包，\pkg{graphics} 宏集。
%   \end{itemize}
%   \item[\ding{229}] 以上是使用 \pdfLaTeX{} 或 \LaTeX{} + \dvipdfmx{} 的编译方式所需要
%   的依赖项，其中 \pkg{zhmCJK} 是可选的。
%   \item \pkg{xeCJK} 宏集，它还依赖
%   \begin{itemize}
%     \item \pkg{xtemplate} 宏包，它属于 \pkg{l3packages} 宏集。
%     \item \pkg{fontspec} 宏包。
%   \end{itemize}
%   \item[\ding{229}] 以上是使用 \XeLaTeX{} 编译时的依赖项。
%   \item \pkg{luatexja} 宏包，它还依赖
%   \begin{itemize}
%     \item \pkg{adobemapping} 宏包。
%     \item \pkg{luaotfload} 宏包，它还依赖 \pkg{lualibs} 宏包。
%     \item \pkg{luatexbase} 宏包，它还依赖 \pkg{ctablestack} 宏包。
%     \item \pkg{atbegshi} 宏包。
%     \item \pkg{etoolbox} 宏包。
%     \item \pkg{iftex} 宏包。
%     \item \pkg{infwarerr} 宏包。
%     \item \pkg{ltxcmds} 宏包。
%     \item \pkg{pdftexcmds} 宏包。
%     \item \pkg{xkeyval} 宏包。
%     \item \pkg{chinese-jfm} 宏包。
%   \end{itemize}
%   \item \pkg{fontspec} 宏包。
%   \item[\ding{229}] 以上是使用 \LuaLaTeX{} 编译时的依赖项。
%   \item \pkg{zhmetrics-uptex} 宏包。
%   \item[\ding{229}] 以上是使用 \upLaTeX{} 编译时的依赖项。
% \end{itemize}
%
% 出于一些原因，\pkg{zhmCJK} 尚未被收入 \TeXLive{} 和 \MiKTeX。因此，若
% 你希望使用 \pkg{zhmCJK} 作为 \CTeX{} 宏集的底层中文支持方式，那么你需要自行安装该宏包。
% \pkg{zhmCJK} 的安装较为复杂。我们建议你
% \begin{enumerate}
%   \item 从 CTAN 下载 \pkg{zhmCJK} 宏包的
%   \href{http://mirrors.ctan.org/install/language/chinese/zhmcjk.tds.zip}
%   {TDS 安装包}，
%   \item 按目录结构将文件复制到 \TeX{} 发行版的本地 TDS 根目录，
%   \item 最后执行 \bashcmd{texhash} 刷新 \TeX{} 发行版的 ls-R 数据库以完成安装。
% \end{enumerate}
% 其他细节，可参照其
% \href{http://mirrors.ctan.org/language/chinese/zhmcjk/zhmCJK.pdf}{宏包手册}
% 中第 3 节的指导。
%
% \emph{\CTeX{} 宏集已被 \TeXLive{} 和 \MiKTeX{} 收录，若无特别理由，
% 我们强烈建议用户使用包管理器安装本宏集。}
%
% 若要手工安装，请遵循如下步骤：
% \begin{enumerate}
%   \item 从 CTAN 下载 \CTeX{} 宏集的
%   \href{http://mirrors.ctan.org/install/language/chinese/ctex.tds.zip}
%   {TDS 安装包}，
%   \item 按目录结构将文件复制到 \TeX{} 发行版的本地 TDS 根目录，
%   \item 最后执行 \bashcmd{texhash} 刷新 \TeX{} 发行版的 ls-R 数据库以完成安装。
% \end{enumerate}
%
% \section{开发人员}
%
% \begin{itemize}
% \item 吴凌云 (\email{aloft@ctex.org})
% \item 江疆 (\email{gzjjgod@gmail.com})
% \item 王越 (\email{yuleopen@gmail.com})
% \item 刘海洋 (\email{LeoLiu.PKU@gmail.com})
% \item 李延瑞 (\email{LiYanrui.m2@gmail.com})
% \item 陈之初 (\email{zhichu.chen@gmail.com})
% \item 李清 (\email{sobenlee@gmail.com})
% \item 黄晨成 (\email{liamhuang0205@gmail.com})
% \item 曾祥东 (\email{xdzeng96@gmail.com})
% \item 李泽平 (\email{zepinglee@gmail.com})
% \item 周宇恺 (\email{muzimuzhi@gmail.com})
% \item 张瑞熹 (\email{ruixizhang42@gmail.com})
% \end{itemize}
%
%
%
% \begin{thebibliography}{9}
% \bibitem{knuthtex1986}
% \textsc{Donald~Ervin Knuth}.
% \newblock \textit{The {{\TeX{}book}}}, \textit{Computers \&amp; Typesetting},
%   volume~A.
% \newblock Addison-Wesley, 1986
%
% \bibitem{mittelbach2004}
% \textsc{Frank Mittelbach} and \textsc{Michel Goossens}.
% \newblock \textit{The {{\LaTeX}} Companion}.
% \newblock Tools and Techniques for Computer Typesetting. Boston:
%   Addison-Wesley, second edition, 2004
%
% \end{thebibliography}
%
% \end{documentation}
%
%
% \StopEventually{}
%
%
%\begin{implementation}
% \clearpage
% \section{代码实现}
%
%    \begin{macrocode}
%&lt;@@=ctex&gt;
%    \end{macrocode}
%
% \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}
%&lt;*class|style&gt;
\cs_if_exist:NF \NewDocumentCommand
  { \RequirePackage { xparse } }
%&lt;class&gt;\prop_gput:Nnn \g_msg_module_type_prop { ctex } { Class }
%&lt;article&gt;\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexart }
%&lt;book&gt;\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexbook }
%&lt;report&gt;\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexrep }
%&lt;beamer&gt;\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexbeamer }
%&lt;ctexsize&gt;\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexsize }
%&lt;ctexheading&gt;\prop_gput:Nnn \g_msg_module_name_prop { ctex } { ctexheading }
%&lt;/class|style&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*class|ctex&gt;
%    \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）。}
%
% 检查 \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 } { 2021/02/10 } { }
  { \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:Nx \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:Nx \c_@@_engine_file_str
      { ctex-engine- \c_@@_engine_str .def }
  }
  { \msg_critical:nnx { ctex } { engine-not-supported } { \c_@@_engine_str } }
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
%&lt;/class|ctex&gt;
%    \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}
%&lt;*class|ctex|ctexheading|ctexsize&gt;
%    \end{macrocode}
%
% \pkg{ctexsize} 也要载入 \pkg{fix-cm} 包解决传统 cm 字体字号缺失的问题。
%    \begin{macrocode}
%&lt;!ctexsize&gt;\RequirePackage { ctexhook , ctexpatch }
%&lt;!ctexheading&gt;\RequirePackage { fix-cm }
%    \end{macrocode}
%
% 宏包载入检查。
%    \begin{macrocode}
%&lt;*class|ctex&gt;
%&lt;*class&gt;
\ctex_disable_package:n { ctex }
\ctex_disable_package:n { ctexcap }
%&lt;/class&gt;
\ctex_disable_package:n { ctexsize }
\ctex_disable_package:n { ctexheading }
%&lt;/class|ctex&gt;
%    \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}
%&lt;*!ctexsize&gt;
%&lt;*!ctexheading&gt;
\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 }
  }
%&lt;/!ctexheading&gt;
%    \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
%&lt;!ctexheading&gt;\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}
%&lt;/!ctexsize&gt;
\cs_new_protected:Npn \ctex_define_option:n
  { \keys_define:nn { ctex / option } }
%&lt;*!ctexsize&gt;
\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}
%&lt;*!beamer&gt;
\int_new:N \g_@@_section_depth_int
\int_gset:Nn \g_@@_section_depth_int { 2 }
%&lt;/!beamer&gt;
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
%&lt;/!ctexsize&gt;
%&lt;/class|ctex|ctexheading|ctexsize&gt;
%&lt;*class|ctex&gt;
%    \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:Nx #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}
%&lt;class&gt;\cs_new_protected:Npn \ctex_at_end:n { \AtEndOfClass }
%&lt;ctex&gt;\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}
%&lt;*class&gt;
\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
%&lt;/class&gt;
%    \end{macrocode}
% \end{variable}
%
% 对无效选项给出警告。
%    \begin{macrocode}
\msg_new:nnn { ctex } { invalid-option }
  { Option~`\l_keys_key_tl'~is~invalid~in~current~mode. }
\msg_new:nnn { ctex } { invalid-value }
  { Value~`#1'~is~invalid~for~the~key~`\l_keys_key_tl'. }
%    \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:nnxx { ctex } { deprecated-command }
      { \token_to_str:N #1 } { \exp_not:n {#2} }
  }
\msg_new:nnn { ctex } { deprecated-option }
  { Option~`\l_keys_key_tl'~is~deprecated.\\ #1 }
\msg_new:nnn { ctex } { deprecated-command }
  { Command~`#1'~is~deprecated.\\ #2 }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%&lt;/class|ctex&gt;
%    \end{macrocode}
%
% \begin{variable}{\g_@@_font_size_int}
% |0| 表示修改默认字体大小为五号，|1| 为小四号，大于 1 则不作修改。初始值 |-1|
% 表示 \opt{zihao} 选项未初始化，会在将来根据文档类决定初值。
%    \begin{macrocode}
%&lt;*class|ctex|ctexsize&gt;
\int_new:N \g_@@_font_size_int
\int_gset:Nn \g_@@_font_size_int { -1 }
%&lt;/class|ctex|ctexsize&gt;
%    \end{macrocode}
% \end{variable}
%
% \subsection{宏包选项}
%
% \changes{v2.3}{2015/09/25}
%   {\texttt{.value_required:} 和 \texttt{.value_forbidden:} 已过时。}
%
%   \begin{macrocode}
%&lt;*class|style&gt;
\ctex_define_option:n
  {
%&lt;/class|style&gt;
%    \end{macrocode}
%
% \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}
%&lt;*class|ctex|ctexsize&gt;
    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 } } ,
%&lt;ctexsize&gt;  }
%&lt;/class|ctex|ctexsize&gt;
%&lt;*class|ctex&gt;
    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 }
      {
        \exp_args:Ne \ctex_at_end:n
          { \ctex_set:n { space = \l_keys_choice_tl } }
      } ,
    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}
%&lt;/class|ctex&gt;
%&lt;*class|ctex|ctexheading&gt;
%    \end{macrocode}
%
% \begin{macro}{sub3section,sub4section}
% \begin{macrocode}
%&lt;*!beamer&gt;
    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 ,
%&lt;/!beamer&gt;
%    \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 ,
%&lt;*ctexheading&gt;
    scheme .default:n = { plain } ,
    scheme .initial:n = { plain }
  }
%&lt;/ctexheading&gt;
%&lt;*!ctexheading&gt;
    scheme .default:n = { chinese } ,
    scheme .initial:n = { chinese } ,
%&lt;/!ctexheading&gt;
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%&lt;/class|ctex|ctexheading&gt;
%&lt;*class|ctex&gt;
%    \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}
%&lt;/class|ctex&gt;
%&lt;*class|ctex|ctexsize&gt;
%    \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 =
%&lt;*!class&gt;
          { \int_gset:Nn \g_@@_font_size_int { 2 } } ,
%&lt;/!class&gt;
%&lt;*class&gt;
          {
            \int_gset:Nn \g_@@_font_size_int { 2 }
            \clist_gput_right:Nn \g_@@_std_options_clist {#1}
          } ,
%&lt;/class&gt;
        #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}
%&lt;*class&gt;
\ctex_define_option:n
  {
    unknown .code:n =
      { \clist_gput_right:No \g_@@_std_options_clist { \CurrentOption } }
  }
%&lt;/class&gt;
%    \end{macrocode}
%
% 载入选项配置文件。
%    \begin{macrocode}
%&lt;!ctexsize&gt;\ctex_file_input:n { ctexopts.cfg }
%&lt;/class|ctex|ctexsize&gt;
%    \end{macrocode}
%
% 处理宏包选项。
%    \begin{macrocode}
%&lt;*class|style&gt;
\cs_if_exist:NTF \ProcessKeyOptions
  { \ProcessKeyOptions [ ctex / option ] }
  {
    \RequirePackage { l3keys2e }
    \ProcessKeysOptions { ctex / option }
  }
%&lt;/class|style&gt;
%    \end{macrocode}
%
% \pdfLaTeX{} 下，如果没有显式指定编码为 |UTF8|，则给出警告信息。
%    \begin{macrocode}
%&lt;*class|ctex&gt;
\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 }
  }
%&lt;/class|ctex&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*class&gt;
%    \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}
%&lt;*article&gt;
\ctex_load_std_class:n { article }
%&lt;/article&gt;
%&lt;*book&gt;
\ctex_load_std_class:n { book }
%&lt;/book&gt;
%&lt;*report&gt;
\ctex_load_std_class:n { report }
%&lt;/report&gt;
%&lt;*beamer&gt;
\ctex_load_std_class:n { beamer }
%&lt;/beamer&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/class&gt;
%    \end{macrocode}
%
% \subsection{特定引擎支持与设置}
%
% \changes{v2.5}{2020/04/22}{给 \LaTeX 和 \upLaTeX 下的文档类指定驱动为 \dvipdfmx。}
%
% \subsubsection{\pkg{ctexbackend.cfg}}
%
% 对于 \XeLaTeX{}/\pdfLaTeX{}/\LuaLaTeX{} 等默认直接输出 PDF 的编译方式，用户
% 无需为涉及驱动的宏包指定驱动选项。对于 \LaTeX 和 \upLaTeX{} 等默认不直接输出 PDF 的编译方式，
% 用户则需要指定驱动选项。
%
% 由于历史遗留问题，在使用 \LaTeX{} 或 \upLaTeX{} 等编译时，
% 大多数涉及驱动的宏包选定的默认输出驱动都是 Dvips。
% 考虑当前实际使用频率，以及考虑到 \CTeX{} 宏集对中文支持的默认方式，
% 我们在用户使用 \CTeX{} 系列文档类时，将默认的输出驱动改为 \dvipdfmx。
%
% 具体来说，如果 |dvips|，|dvipdfmx|，|dvisvgm| 等驱动没有在文档类的全局选项中被明确指定，
% 我们就在 \tn{@classoptionslist} 开头加入 |dvipdfmx|。
%
% 本段代码只在 \cls{ctexart} 等文档类开头载入，不在 \pkg{ctex} 中使用。
% 并且需要放在 \pkg{expl3} 之前载入，保证它载入正确的 backend 文件。
%    \begin{macrocode}
%&lt;*backend&gt;
\begingroup
\expandafter\ifx\csname Umathchardef\endcsname\relax
\else\expandafter\endgroup\expandafter\endinput\fi
  \ifodd
    \expandafter\ifx\csname      pdfoutput\endcsname\relax
    \expandafter\ifx\csname enablecjktoken\endcsname\relax 0\else 1\fi
                                   \else\ifnum\pdfoutput&gt;0 0\else 1\fi\fi\space
    \def\x#1{%
      \if\relax\detokenize{#1}\relax
        \gdef\@classoptionslist{dvipdfmx}%
      \else
        \let\CTEX@add\@ne
        \@tfor\x:={dvips}{dvipdfmx}{dvisvgm}\do{%
          \expandafter\in@\expandafter{\expandafter,\x,}{,#1,}%
          \ifin@ \let\CTEX@add\tw@ \@break@tfor \fi}%
        \ifodd\CTEX@add \gdef\@classoptionslist{dvipdfmx,#1}\fi
      \fi}
    \expandafter\x\expandafter{\@classoptionslist}
  \fi
\endgroup
%&lt;/backend&gt;
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-engine-pdftex.def}}
%
% \begin{macro}[int]{\ctex_set_zhmap:n}
% 设置 \upTeX{} 字体映射，同时作用于 \tn{AtBeginDvi} 与
% \tn{AtBeginShipoutFirst}。该宏对 \pdfTeX{} 和 \upTeX{} 均有用。
% \tn{AtBeginDvi} 直接将 \tn{special} 保存到盒子中，
% \tn{AtBeginShipoutFirst} 是保存到到宏中，并且不展开参数。
%
% 可以使用 \LaTeX\ 2020/10/01 的钩子机制来统一设置。
%     \begin{macrocode}
%&lt;*pdftex|uptex|aptex&gt;
\cs_new_protected:Npn \ctex_set_zhmap:n
  { \tl_gput_right:Nx \g_@@_zhmap_tl }
\cs_new_protected:Npn \ctex_use_zhmap:
  { \tl_use:N \g_@@_zhmap_tl }
\cs_if_exist:NTF \ctex_gadd_ltxhook:nn
  {
    \cs_new_protected:Npn \ctex_at_shipout_first:n
      { \ctex_gadd_ltxhook:nn { shipout/firstpage } }
    \ctex_at_shipout_first:n { \ctex_use_zhmap: }
  }
  {
    \cs_new_protected:Npn \ctex_add_dvi_zhmap:
      { \AtBeginDvi { \ctex_use_zhmap: } }
    \ctex_after_end_preamble:n { \ctex_add_dvi_zhmap: }
    \ctex_at_end_package:nn { atbegshi }
      {
        \cs_new_protected:Npn \ctex_at_shipout_first:n
          { \AtBeginShipoutFirst }
        \ctex_at_shipout_first:n { \ctex_use_zhmap: }
        \cs_gset_eq:NN \ctex_add_dvi_zhmap: \prg_do_nothing:
      }
  }
\tl_new:N \g_@@_zhmap_tl
\@onlypreamble \ctex_set_zhmap:n
%&lt;/pdftex|uptex|aptex&gt;
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%&lt;*pdftex&gt;
%    \end{macrocode}
%
% \changes{v2.1}{2015/05/18}{给 \pdfLaTeX{} 下的非 UTF-8 编码 CJK 字体族加上 CMap。}
%
% \begin{variable}{\c_@@_cmap_encoding_seq}
% 需要加上 CMap 的 CJK 字体编码。
%    \begin{macrocode}
\seq_const_from_clist:Nn \c_@@_cmap_encoding_seq
  { C19 , C10 , C00 , C09 , C40 , C60 }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[int]{\ctex_family_cmap:nn}
% 在 \tn{DeclareFontFamily} 的 \meta{loading-settings} 中给 CJK 字体族加上 CMap。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_family_cmap:nn #1#2
  {
    \cs_if_free:cF { #1 + #2 }
      {
        \seq_if_in:NnT \c_@@_cmap_encoding_seq {#1}
          { \tl_gput_right:cn { #1 + #2 } { \ctex_add_cmap:n {#1} } }
      }
  }
\cs_generate_variant:Nn \ctex_family_cmap:nn { ee }
\cs_new_eq:NN \CTEX@Family@CMap \ctex_family_cmap:ee
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.7}{2021/06/06}{更好地兼容 \pkg{cmap} 包。}
%
% \begin{macro}[int]{\ctex_add_cmap:n}
% \changes{v2.5.7}{2021/06/06}{确保 cmap 文件存在。}
% \changes{v2.5.10}{2022/07/11}{使用封装好的函数。}
% 给 |#1| 编码的 CJK 字体加上 CMap。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_add_cmap:n #1
  {
    \cs_if_free:NF \CJK@plane
      { \exp_args:Ne \@@_add_cmap_auxi:n { #1 \CJK@plane } }
  }
\cs_new_protected:Npn \@@_add_cmap_auxi:n #1
  { \exp_args:Nc \@@_add_cmap_auxii:Nn { @@_add_cmap_ #1 : } {#1} }
\cs_new_protected:Npn \@@_add_cmap_auxii:Nn #1#2
  {
    \cs_if_exist:NF #1 { \@@_save_cmap:Nn #1 {#2} }
    #1
  }
\cs_new_protected:Npn \@@_save_cmap:Nn #1#2
  {
    \exp_args:Ne \file_get_full_name:nNTF
      { \str_lowercase:n {#2} .cmap } \l_@@_cmap_file_tl
      {
        \pdf_object_unnamed_write:nx
          { fstream }
          { { } { \l_@@_cmap_file_tl } }
        \cs_new_protected:Npx #1
          {
            \pdfnobuiltintounicode \tex_font:D
            \tex_pdffontattr:D \tex_font:D
              { /ToUnicode ~ \pdf_object_ref_last: }
          }
      }
      { \cs_new_eq:NN #1 \prg_do_nothing: }
  }
\tl_new:N \l_@@_cmap_file_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\DeclareFontFamily}
% 只在 \pdfLaTeX{} 下加 CMap。如 \pkg{cmap} 宏包被引入，则不重复设置。
%    \begin{macrocode}
\sys_if_output_pdf:T
  {
    \exp_args:Nno \use:n
      { \cs_gset_protected:Npn \DeclareFontFamily #1#2#3 }
      {
        \DeclareFontFamily {#1} {#2} {#3}
        \CTEX@Family@CMap  {#1} {#2}
      }
    \ctex_at_end_package:nn { cmap }
      {
        \cs_gset_eq:NN \ctex_add_cmap:n \use_none:n
        \cs_gset_eq:NN \CTEX@Family@CMap \use_none:nn
      }
  }
%    \end{macrocode}
% \end{macro}
%
% 首先检查选项，决定是否载入 \pkg{zhmCJK} 宏包。
%    \begin{macrocode}
\bool_if:NTF \g_@@_zhmCJK_bool
  {
    \exp_args:Ne \PassOptionsToPackage
      { encoding = \g_@@_encoding_tl }
      { zhmCJK }
    \RequirePackage { zhmCJK }
  }
%    \end{macrocode}
% 不载入 \pkg{zhmCJK} 宏包时直接调用 \pkg{CJK} 及相关宏包。
%    \begin{macrocode}
  {
    \str_if_eq:onTF { \g_@@_encoding_tl } { GBK }
      { \RequirePackage { CJK } }
      { \RequirePackage { CJKutf8 } }
    \RequirePackage { CJKpunct , CJKspace }
%    \end{macrocode}
%
% \changes{v2.4.4}{2016/09/09}{解决 \opt{zhmap} 文件的 \tn{catcode} 问题。}
%
% \begin{macro}[int]{\ctex_load_zhmap:nnnn}
% 载入 \pkg{zhmetrics} 的字体映射文件，同时设置 \tn{CJKrmdefault} 等。
%    \begin{macrocode}
    \cs_new_protected:Npn \ctex_load_zhmap:nnnn #1#2#3#4
      {
        \tl_set:Nn \CJKrmdefault {#1}
        \tl_set:Nn \CJKsfdefault {#2}
        \tl_set:Nn \CJKttdefault {#3}
        \ctex_set_zhmap:n { \ctex_file_input:n { ctex-zhmap- #4 .tex } }
      }
    \@onlypreamble \ctex_load_zhmap:nnnn
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.10}{2022/06/10}{取消 \LaTeX\ 2022-06-01 对书名号的定义。}
%
% \begin{macro}{\ctex_undeclare_unicode_character:n,\ctex_utfviii_char:n}
% \LaTeX\ 2022-06-01 将通常用作中文书名号的 U+3008 和 U+3009 分别定义为
% \tn{textlangle} 和 \tn{textrangle}，这个定义会被 \pkg{CJKutf8} 包会优先使用。
% 我们总是使用中文书名号，需要取消 \LaTeX\ 的定义，作用是局部的，不使用 \cs{cs_undefine:N}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_undeclare_unicode_character:n #1
  { \cs_set_eq:cN { u8 : \ctex_utfviii_char:n {#1} } \tex_undefined:D }
\cs_new:Npn \ctex_utfviii_char:n #1
  {
    \exp_last_unbraced:Ne \@@_utfviii_char_aux:nnnn
      { \char_to_utfviii_bytes:n {#1} }
  }
\cs_new:Npn \@@_utfviii_char_aux:nnnn #1#2#3#4
  {
    \char_generate:nn {#1} { 12 }
    \tl_if_empty:nF {#2} { \char_generate:nn {#2} { 12 } }
    \tl_if_empty:nF {#3} { \char_generate:nn {#3} { 12 } }
    \tl_if_empty:nF {#4} { \char_generate:nn {#4} { 12 } }
  }
\CJKaddEncHook { UTF8 }
  {
    \ctex_undeclare_unicode_character:n { "3008 }
    \ctex_undeclare_unicode_character:n { "3009 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_CJK_input:n,\CJK@input}
% 载入 \pkg{CJK} 包的 \file{.enc} 和 \file{.bdg} 等文件时，需要设置 \tn{endlinechar} 为 $-1$。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_CJK_input:n #1
  {
    \ctex_push_file:
      \int_set:Nn \tex_endlinechar:D { -1 }
      \file_input:n {#1}
    \ctex_pop_file:
  }
\cs_set_eq:NN \CJK@input \ctex_CJK_input:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_plane_to_utfxvibe:Nn,\CJK@surr}
% \changes{v2.0}{2014/04/08}{解决与 \tn{nouppercase} 的冲突。}
% \pkg{fancyhdr} 宏包的 \tn{nouppercase} 会将 \tn{uppercase} 定义为 \tn{relax}，而
% \tn{CJK@surr} 需要用它将 \tn{CJK@plane} 转化成大写字母，这就造成了冲突^^A
% \footnote{\url{https://github.com/CTeX-org/ctex-kit/issues/146}}。
% 我们在这里给出 \tn{CJK@surr} 的一个不依赖 \tn{uppercase} 的实现。
%    \begin{macrocode}
\cs_if_free:NF \CJK@surr
  {
    \cs_new_protected:Npn \ctex_plane_to_utfxvibe:Nn #1#2
      {
        \int_set:Nn \l_@@_tmp_int
          { \exp_args:Ne \int_from_hex:n {#2} }
        \int_compare:nNnTF \l_@@_tmp_int &lt; { 256 }
          { \tl_gset:Nx #1 { \int_to_Hex:n { \l_@@_tmp_int } } }
          {
            \int_sub:Nn \l_@@_tmp_int { 256 }
            \tl_gset:Nx #1
              {
                \int_to_Hex:n
                  { \int_div_truncate:nn { \l_@@_tmp_int } { 4 } + "D800 }
                \int_to_Hex:n
                  { \int_mod:nn { \l_@@_tmp_int } { 4 } + "DC }
              }
          }
      }
    \cs_set_eq:NN \CJK@surr \ctex_plane_to_utfxvibe:Nn
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\CJK@addcmap}
% \changes{v2.5.7}{2021/06/06}{应用 \tn{pdfnobuiltintounicode}。}
% \LaTeX \ 2021-06-01 默认载入 \file{glyphtounicode.tex}，我们对 CJK 字体禁用这一内建设置。
%    \begin{macrocode}
\cs_if_free:NF \CJK@addcmap
  {
    \ctex_patch_cmd:Nnn \CJK@addcmap
      { \pdffontattr \font@name }
      {
        \pdfnobuiltintounicode \font@name
        \pdffontattr \font@name
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \pkg{CJKpunct} 宏包会在 \tn{AtBeginDocument} 的里设置标点格式为 \opt{quanjiao}。
%    \begin{macrocode}
\AtBeginDocument
  {
    \use:e
      {
        \str_if_eq:nnF { \l_@@_punct_tl } { quanjiao }
          { \exp_not:N \punctstyle { \l_@@_punct_tl } }
      }
  }
%    \end{macrocode}
%
% 在导言区末尾更新 \tn{CJKfamilydefault}，注意要在 \tn{CJK@envStart} 之前使用。
%    \begin{macrocode}
\ctex_at_end_preamble:n { \ctex_update_default_family: }
%    \end{macrocode}
%
% 从 \LaTeX\ 2018-04-01 开始，传统引擎的默认编码被设置成 UTF-8，
% 汉字的首字节已经被设置成活动字符，我们无需再使用 \tn{CJK@makeActive} 设置。
% \tn{CJK@envStart} 的定义是
% \begin{verbatim}
%   \def\CJK@envStart#1#2#3{
%     \CJK@upperReset
%     \ifCJK@lowercase@
%       \CJK@lowerReset
%     \fi%
%     \CJK@makeActive%
%     \CJK@global\let\CJK@selectFamily \CJK@selFam
%     \CJK@global\let\CJK@selectEnc \CJK@selEnc%
%     \def\CJK@@@enc{#2}
%     \ifx\CJK@@@enc \@empty
%       \PackageInfo{CJK}{
%         no encoding parameter given,\MessageBreak
%         waiting for \protect\CJKenc\space commands}
%     \else
%       \CJKenc{#2}
%     \fi
%     \CJKfontenc{#2}{#1}
%     \CJKfamily{#3}
%     \def\CJK@series{\f@series}
%     \def\CJK@shape{\f@shape}%
%     \csname CJKhook\endcsname}
% \end{verbatim}
% \tn{CJK@upperReset} 可能会有一定风险，因此我们直到导言区末尾才使用
% \tn{CJK@envStart}。这样可以避免将 \env{CJK} 环境内置入 \env{document} 环境的
% 最里层，最后也就不需要 \tn{clearpage}。\pkg{zhmCJK} 已经提供类似功能。
% 注意先使用 \cs{ctex_update_default_family:} 更新 \tn{CJKfamilydefault}。
%    \begin{macrocode}
\bool_if:NF \g_@@_zhmCJK_bool
  {
    \str_if_eq:onTF { \g_@@_encoding_tl } { UTF8 }
      { \CJK@loadBinding { UTF8 } }
      { \CJK@loadBinding { standard } }
    \exp_args:Ne \ctex_at_end_preamble:n
      {
        \exp_not:N \CJK@envStart
          { } { \g_@@_encoding_tl } { \exp_not:N \CJKfamilydefault }
        \exp_not:N \CJKtilde
      }
  }
%    \end{macrocode}
%
% \begin{macro}[int]{\ctex_auto_ignorespaces:}
% 保存 \tn{CJK@@ignorespaces} 的定义，方便使用。
%    \begin{macrocode}
\cs_new_eq:NN \ctex_auto_ignorespaces: \CJK@@@@ignorespaces
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.10}{2022/07/08}{解决 \pkg{CJK} 包与 \cs{text_uppercase:n} 等转化函数的冲突。}
%
% \begin{macro}{\CJK@X,\CJK@XX,\CJK@XXX,\CJK@XXXX}
% 最新 \LaTeX\ 中的 \tn{MakeUppercase} 等大小写转化命令被定义为 \LaTeXiii\ 中对应的
% \cs{text_uppercase:n} 等函数。
% 它会先将参数用 \cs{text_expand:n} 逐步展开，这与 \pkg{CJK} 包的定义不兼容。
% 可以有多种方法解决这个冲突，最简单直接的方法是将首字节的活动字符用 \tn{protected} 来定义，
% 但可能有一定的兼容性问题。保险起见，我们采用将 \tn{CJK@X} 等内部宏转化为 \tn{protected}
% 宏的方式，并将参数提前由字符转化为数字，避免在移动参数中被进一步展开。
%    \begin{macrocode}
\cs_new:Npn \@@_char:N #1
  { \exp_args:Ne \CTEX@char@n { \int_value:w `#1 } }
\cs_new:Npn \@@_char:NN #1#2
  {
    \token_if_eq_meaning:NNTF #2 \protect
      { \@@_char_aux:NN #1 }
      { \@@_char_aux:NN #1#2 }
  }
\cs_new:Npn \@@_char_aux:NN #1#2
  {
    \exp_last_unbraced:Ne \CTEX@char@nn
      {
        { \int_value:w `#1 }
        { \int_value:w `#2 }
      }
  }
\cs_new:Npn \@@_char:NNN #1#2#3
  {
    \token_if_eq_meaning:NNTF #2 \protect
      { \@@_char_auxi:NNNN #1#3 }
      { \@@_char_auxii:NNN #1#2#3 }
  }
\cs_new:Npn \@@_char_auxi:NNN #1#2#3#4
  { \@@_char_auxii:NNN #1#2#4 }
\cs_new:Npn \@@_char_auxii:NNN #1#2#3
  {
    \exp_last_unbraced:Ne \CTEX@char@nnn
      {
        { \int_value:w `#1 }
        { \int_value:w `#2 }
        { \int_value:w `#3 }
      }
  }
\cs_new:Npn \@@_char:NNNN #1#2#3#4
  {
    \token_if_eq_meaning:NNTF #2 \protect
      { \@@_char_auxi:NNNNN #1#3 }
      { \@@_char_auxii:NNNN #1#2#3#4 }
  }
\cs_new:Npn \@@_char_auxi:NNNNN #1#2#3#4#5
  { \@@_char_auxii:NNNN #1#2#3#5 }
\cs_new:Npn \@@_char_auxii:NNNN #1#2#3#4
  {
    \exp_last_unbraced:Ne \CTEX@char@nnnn
      {
        { \int_value:w `#1 }
        { \int_value:w `#2 }
        { \int_value:w `#3 }
        { \int_value:w `#4 }
      }
  }
\cs_gset_eq:NN \CJK@X    \@@_char:N
\cs_gset_eq:NN \CJK@XX   \@@_char:NN
\cs_gset_eq:NN \CJK@XXX  \@@_char:NNN
\cs_gset_eq:NN \CJK@XXXX \@@_char:NNNN
%    \end{macrocode}
% \pkg{CJKutf8} 包优先使用 |\u8:xxx| 的 \LaTeX\ 定义。
%    \begin{macrocode}
\str_if_eq:onF { \g_@@_encoding_tl } { GBK }
  {
    \exp_args:Nne \use:n
      { \cs_gset:Npn \@@_char_aux:NN #1#2 }
      {
        \exp_not:N \cs_if_exist_use:cF
          { u8: \exp_not:N \tl_to_str:n { #1#2 } }
          { \exp_not:o { \@@_char_aux:NN {#1} {#2} } }
      }
    \exp_args:Nne \use:n
      { \cs_gset:Npn \@@_char_auxii:NNN #1#2#3 }
      {
        \exp_not:N \cs_if_exist_use:cF
          { u8: \exp_not:N \tl_to_str:n { #1#2#3 } }
          { \exp_not:o { \@@_char_auxii:NNN {#1} {#2} {#3} } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\mule@arg}
% 处理文档被 |extconv| 等工具预处理过的情况，只考虑最简单的情形。
%    \begin{macrocode}
\group_begin:
\char_set_catcode_active:n { "7F }
\cs_new:Npn \@@_char_preproc:w #1 ^^7f #2 ^^7f
  { \exp_args:No \CTEX@char@nn { \int_value:w `#1 } {#2} }
\cs_gset_eq:NN \mule@arg \@@_char_preproc:w
\group_end:
\exp_args:Ne \ctex_at_end:n
  {
    \char_set_catcode:nn
      { \int_value:w "7F }
      { \char_value_catcode:n { "7F } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CTEX@char@n,\CTEX@char@nn,\CTEX@char@nnn,\CTEX@char@nnnn}
% 额外加入 \cs{mode_leave_vertical:} 是为了解决某些历史遗留问题。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@char@n #1
  {
    \mode_leave_vertical:
    \use:c { CJK@ #1 }
    \CJK@ignorespaces
  }
\cs_new_protected:Npn \CTEX@char@nn #1#2
  {
    \mode_leave_vertical:
    \use:c { CJK@ #1 } {#2}
    \CJK@ignorespaces
  }
\cs_new_protected:Npn \CTEX@char@nnn  #1#2#3
  {
    \mode_leave_vertical:
    \use:c { CJK@ #1 } {#2} {#3}
    \CJK@ignorespaces
  }
\cs_new_protected:Npn \CTEX@char@nnnn #1#2#3#4
  {
    \mode_leave_vertical:
    \use:c { CJK@ #1 } {#2} {#3} {#4}
    \CJK@ignorespaces
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CTEX@char@nn@n,\CTEX@char@nnn@n,\CTEX@char@nnnn@n}
% 以下给 \tn{CTEX@char@nn} 等定义在 \cs{text_expand:n} 中的等价形式，
% 将它们的参数用只有一个参数的 \tn{CTEX@char@nn@n} 等包装起来，
% 并将 \tn{CTEX@char@nn@n} 等放入排除列表中，避免可能的大小写转化。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@char@nn@n   #1 { \CTEX@char@nn   #1 }
\cs_new_protected:Npn \CTEX@char@nnn@n  #1 { \CTEX@char@nnn  #1 }
\cs_new_protected:Npn \CTEX@char@nnnn@n #1 { \CTEX@char@nnnn #1 }
\cs_new:Npn \@@_char_wrap:nn #1#2
  { \CTEX@char@nn@n   { {#1} {#2} } }
\cs_new:Npn \@@_char_wrap:nnn #1#2#3
  { \CTEX@char@nnn@n  { {#1} {#2} {#3} } }
\cs_new:Npn \@@_char_wrap:nnnn #1#2#3#4
  { \CTEX@char@nnnn@n { {#1} {#2} {#3} {#4} } }
\tl_put_right:Nn \l_text_case_exclude_arg_tl
  {
    \CTEX@char@n
    \CTEX@char@nn@n
    \CTEX@char@nnn@n
    \CTEX@char@nnnn@n
  }
\text_declare_expand_equivalent:Nn \CTEX@char@nn   { \@@_char_wrap:nn }
\text_declare_expand_equivalent:Nn \CTEX@char@nnn  { \@@_char_wrap:nnn }
\text_declare_expand_equivalent:Nn \CTEX@char@nnnn { \@@_char_wrap:nnnn }
%    \end{macrocode}
% 以下给 \tn{CTEX@char@nn@n} 等定义在 \cs{text_purify:n} 中的等价形式，
% 将参数中的数字转化回字符。
%    \begin{macrocode}
\cs_new:Npn \@@_char_raw:n #1
  { \char_generate:nn {#1} { 12 } }
\cs_new:Npn \@@_char_raw:nn #1#2
  {
    \char_generate:nn {#1} { 12 }
    \char_generate:nn {#2} { 12 }
  }
\cs_new:Npn \@@_char_raw:nnn #1#2#3
  {
    \char_generate:nn {#1} { 12 }
    \char_generate:nn {#2} { 12 }
    \char_generate:nn {#3} { 12 }
  }
\cs_new:Npn \@@_char_raw:nnnn #1#2#3#4
  {
    \char_generate:nn {#1} { 12 }
    \char_generate:nn {#2} { 12 }
    \char_generate:nn {#3} { 12 }
    \char_generate:nn {#4} { 12 }
  }
\cs_new:Npn \@@_char_raw_nn:n   #1 { \use:e { \@@_char_raw:nn   #1 } }
\cs_new:Npn \@@_char_raw_nnn:n  #1 { \use:e { \@@_char_raw:nnn  #1 } }
\cs_new:Npn \@@_char_raw_nnnn:n #1 { \use:e { \@@_char_raw:nnnn #1 } }
\text_declare_purify_equivalent:Nn \CTEX@char@n      { \@@_char_raw:n }
\text_declare_purify_equivalent:Nn \CTEX@char@nn@n   { \@@_char_raw_nn:n }
\text_declare_purify_equivalent:Nn \CTEX@char@nnn@n  { \@@_char_raw_nnn:n }
\text_declare_purify_equivalent:Nn \CTEX@char@nnnn@n { \@@_char_raw_nnnn:n }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ignorespaces_case:N,\ctex_set_ignorespaces:}
% 设置忽略空格的的方式。根据 \opt{space} 选项的值重定义 \tn{CJK@ignorespaces}，
% 并保存起来供 \tn{CJKhook} 备用。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ignorespaces_case:N #1
  {
    \cs_set_protected:Npn \ctex_set_ignorespaces:
      { \cs_set_eq:NN \CJK@ignorespaces #1 }
    \ctex_set_ignorespaces:
  }
\cs_new_protected:Npn \ctex_set_ignorespaces:
  { \cs_set_eq:NN \CJK@ignorespaces \ctex_auto_ignorespaces: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\CJKhook}
% \changes{v2.5.5}{2020/10/06}{不再通过旧的钩子命令来定义。}
% \env{CJK} 和 \env{CJK*} 环境都会重新定义 \tn{CJK@ignorespaces}。我们在 \pkg{CJK}
% 宏包提供的 \tn{CJKhook} 里重新设置它，让这两个环境忽略空格的方式都受 \opt{space}
% 选项的控制。这对 \pkg{zhmCJK} 是必要的。
%    \begin{macrocode}
\tl_if_exist:NF \CJKhook { \tl_new:N \CJKhook }
\tl_gput_right:Nn \CJKhook { \ctex_set_ignorespaces: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_punct_set:n}
% 设置 CJK 族对应到实际的字体。|#1| 是 \opt{fontset} 的名字。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_punct_set:n #1
  {
    \clist_map_inline:Nn \c_@@_punct_family_clist
      {
        \cs_if_free:cF { c_@@_ #1 ##1 _punct_spaces_tl }
          {
            \cs_set_eq:cc
              { CJKpunct@ ##1 @spaces }
              { c_@@_ #1 ##1 _punct_spaces_tl }
          }
      }
  }
\clist_const:Nn \c_@@_punct_family_clist
  {
    zhsong , zhhei , zhfs , zhkai , zhli , zhyou ,
    zhsongb , zhheil , zhheib , zhyoub ,
    zhyahei , zhyaheib , zhpf , zhpfb
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_punct_map_family:nn}
% CJK 族 |#1| 使用族 |#2| 的边界信息。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_punct_map_family:nn #1#2
  {
    \cs_if_free:cF { CJKpunct@ #2 @spaces }
      { \cs_set_eq:cc { CJKpunct@ #1 @spaces } { CJKpunct@ #2 @spaces } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_punct_map_bfseries:nn}
% CJK 族 |#1| 的 \tn{bfseries} 使用族 |#2| 的边界信息。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_punct_map_bfseries:nn #1#2
  {
    \clist_map_inline:nn {#1}
      {
        \ctex_punct_map_series:nnn { ##1 } { b } {#2}
        \ctex_punct_map_series:nnn { ##1 } { bx } {#2}
      }
  }
\cs_new_protected:Npn \ctex_punct_map_series:nnn #1#2#3
  {
    \CJKpunctmapfamily { C19 } {#1} {#2} { m }  {#3}
    \CJKpunctmapfamily { C19 } {#1} {#2} { it } {#3}
    \CJKpunctmapfamily { C19 } {#1} {#2} { sl } {#3}
    \CJKpunctmapfamily { C70 } {#1} {#2} { m }  {#3}
    \CJKpunctmapfamily { C70 } {#1} {#2} { it } {#3}
    \CJKpunctmapfamily { C70 } {#1} {#2} { sl } {#3}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_punct_map_itshape:nn}
% CJK 族 |#1| 的 \tn{itshape} 使用族 |#2| 的边界信息。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_punct_map_itshape:nn #1#2
  {
    \CJKpunctmapfamily { C19 } {#1} { m }  { it } {#2}
    \CJKpunctmapfamily { C19 } {#1} { b }  { it } {#2}
    \CJKpunctmapfamily { C19 } {#1} { bx } { it } {#2}
    \CJKpunctmapfamily { C70 } {#1} { m }  { it } {#2}
    \CJKpunctmapfamily { C70 } {#1} { b }  { it } {#2}
    \CJKpunctmapfamily { C70 } {#1} { bx } { it } {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_punct_space:nn,\ctexspadef}
% 定义标点的边界信息。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_punct_space:nn #1#2
  { \tl_const:cn { c_@@_ #1 _punct_spaces_tl } {#2} }
\cs_new_eq:NN \ctexspadef \ctex_punct_space:nn
%    \end{macrocode}
% \end{macro}
%
% 载入边界信息文件。
%     \begin{macrocode}
\ctex_file_input:n { ctexspa.def }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/pdftex&gt;
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-engine-xetex.def}}
%
%    \begin{macrocode}
%&lt;*xetex&gt;
%    \end{macrocode}
%
% \changes{v2.4.4}{2016/09/12}{不再默认设置 \pkg{xeCJK} 的伪粗体。}
%    \begin{macrocode}
\RequirePackage { xeCJK }
\exp_args:Ne \xeCJKsetup
  {
    LoadFandol   = false ,
    PunctStyle   = \l_@@_punct_tl
  }
%    \end{macrocode}
%
% 最新版本的 \pkg{fontspec} 默认对 \tn{rmfamily} 和 \tn{sffamily} 设置
% |Ligatures=TeX|，对 \tn{ttfamily} 设置 |WordSpace={1,0,0}| 和
% |PunctuationSpace=WordSpace|。
%    \begin{macrocode}
\@ifpackagelater { fontspec } { 2014/05/25 } { }
  { \msg_error:nnn { ctex } { package-too-old } { fontspec } }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/xetex&gt;
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-engine-luatex.def}}
%
%    \begin{macrocode}
%&lt;*luatex&gt;
%    \end{macrocode}
%
% \changes{v2.0}{2014/03/08}{通过 \pkg{LuaTeX-ja} 宏包支持 \LuaLaTeX。}
% \changes{v2.3}{2015/09/25}{更新 \pkg{LuaTeX-ja} 支持（20150922.0）。}
% \changes{v2.5}{2020/04/18}{更新 \pkg{LuaTeX-ja} 支持（20200412.0）。}
% \changes{v2.5.4}{2020/08/16}{更新 \pkg{LuaTeX-ja} 支持（20200808.0）。}
%
% \pkg{LuaTeX-ja} 为了兼容 p\LaTeX 的使用习惯，对 \LaTeXe 的 \pkg{NFSS} 作了不少
% 修改和扩充，这对于简体中文用户来说不是必要的。我们在这里禁用它。
%    \begin{macrocode}
\msg_new:nnn { ctex } { luatexja-loaded }
  {
    Package~`luatexja'~can~not~be~loaded~before~`ctex'.\\
    Loading~file~`#1'~will~abort!
  }
\@ifpackageloaded { luatexja }
  { \msg_critical:nnx { ctex } { luatexja-loaded } { \g_file_curr_name_str } }
  {
    \ctex_at_begin_package:nn { luatexja }
      { \msg_redirect_name:nnn { ctexhook } { disable-package } { info } }
    \ctex_at_end_package:nn { luatexja }
      { \msg_redirect_name:nnn { ctexhook } { disable-package } { } }
    \ctex_disable_package:n { ltj-latex }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\RequirePackage { luatexja }
\@ifpackagelater { luatexja } { 2020/04/12 } { }
  { \msg_error:nnn { ctex } { package-too-old } { luatexja } }
%    \end{macrocode}
%
%    \begin{macrocode}
\RequirePackage { fontspec }
\@ifpackagelater { fontspec } { 2020/02/21 } { }
  { \msg_error:nnn { ctex } { package-too-old } { fontspec } }
%    \end{macrocode}
%
% 引擎文件是通过 \cs{ctex_file_input:n} 载入的，其中的 \tn{catcodetable} 机制会完整恢复
% 文件载入之前的 \tn{catcode} 状态，在引擎文件中的 \tn{catcode} 设置都无效。
% 因此，对 \tn{ltjlineendcomment} 的设置要放到文件之外进行。
%    \begin{macrocode}
\ctex_at_end:n { \char_set_catcode_comment:n { \ltjlineendcomment } }
%    \end{macrocode}
%
% \paragraph{\pkg{LuaTeX-ja} 的默认设置}
%
%    \begin{macrocode}
\ExplSyntaxOff
%    \end{macrocode}
%
% 以下设置抄录自 \file{lltjdefs.sty}，略有改动。
%
% \changes{v2.4.11}{2017/08/17}{不把 Enclosed Alphanumerics 设置为 JAchar。}
% U+2460--U+24FF (Enclosed Alphanumerics) 原属于字符范围 6，是 JAchar，
% 我们把它们归入字符范围 3，改成  ALchar。
%    \begin{macrocode}
\ltjdefcharrange{1}{"80-"36F, "1E00-"1EFF}
\ltjdefcharrange{2}{"370-"4FF, "1F00-"1FFF}
\ltjdefcharrange{3}{%
  "2000-"243F, "2460-"24FF, "2500-"27BF, "2900-"29FF, "2B00-"2BFF}
\ltjdefcharrange{4}{%
   "500-"10FF, "1200-"1DFF, "2440-"245F, "27C0-"28FF, "2A00-"2AFF,
  "2C00-"2E7F, "4DC0-"4DFF, "A4D0-"A95F, "A980-"ABFF, "E000-"F8FF,
  "FB00-"FE0F, "FE20-"FE2F, "FE70-"FEFF, "10000-"1AFFF, "1B170-"1F0FF,
  "1F300-"1FFFF, "2000-"206F}
\ltjdefcharrange{5}{"D800-"DFFF, "E0000-"E00FF, "E01F0-"10FFFF}
\ltjdefcharrange{6}{%
  "2E80-"2EFF, "3000-"30FF, "3190-"319F, "31F0-"4DBF,
  "4E00-"9FFF, "F900-"FAFF, "FE10-"FE1F, "FE30-"FE6F, "FF00-"FFEF,
  "1B000-"1B16F, "1F100-"1F2FF, "20000-"3FFFF, "E0100-"E01EF}
\ltjdefcharrange{7}{%
  "1100-"11FF, "2F00-"2FFF, "3100-"318F, "31A0-"31EF, "A000-"A4CF,
  "A960-"A97F, "AC00-"D7FF}
\ltjdefcharrange{8}{"A7, "A8, "B0, "B1, "B4, "B6, "D7, "F7}
%    \end{macrocode}
% 将间隔号、引号、破折号等中西文公用的标点符号归入字符范围 9，将他们设置为 JAchar。
%    \begin{macrocode}
\ltjdefcharrange{9}{%
  "00B7, "2018, "2019, "201C, "201D, "2013, "2014, "2025, "2026, "2027, "2E3A}
%    \end{macrocode}
% \changes{v2.4.11}{2017/08/17}{不把希腊和西里尔字母设置为 JAchar。}
% \pkg{LuaTeX-ja} 默认把字符范围 2 和 3 设置为 JAchar，我们这里把它们都改成 ALchar。
%    \begin{macrocode}
\ltjsetparameter{jacharrange={-1, -2, -3, -4, -5, +6, +7, -8, +9}}
\directlua{for x=128,255 do luatexja.math.is_math_letters[x] = true end}
%    \end{macrocode}
%
% 以下设置抄录自 2020/08/08 之前的 \file{ltj-latex.sty}。
% 自 2020/08/08 开始，\pkg{LuaTeX-ja} 引入新的缓存机制，此段设置被整合进 \file{luatexja.lua}。
%    \begin{macrocode}
\@ifpackagelater{luatexja}{2020/08/08}
  { \ltjsetparameter { autospacing, autoxspacing, differentjfm = paverage } }
  {
    \directlua{
      local s = kpse.find_file('ltj-kinsoku.lua', 'tex')
      luatexja.stack.charprop_stack_table[0] = s and dofile(s) or {}
    }
    \ltjsetparameter{kanjiskip=\z@ plus .4pt minus .5pt,
      xkanjiskip=.25\zw plus 1pt minus 1pt,
      autospacing, autoxspacing, jacharrange={-1},
      yalbaselineshift=\z@, yjabaselineshift=\z@,
      jcharwidowpenalty=500, differentjfm=paverage
    }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
% \paragraph{\pkg{LuaTeX-ja} 的补丁}
%
%    \begin{macrocode}
%&lt;@@=ctex_ltj&gt;
%    \end{macrocode}
%
% \changes{v2.5.3}{2020/05/31}{不再依赖 \pkg{xunicode}，单独补丁 \file{tuenc.def}。}
%
% \begin{macro}{\CTEX@alchar, \CTEX@beginallalchar, \CTEX@endallalchar}
% 分组中的字符都是 ALchar 类。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@alchar #1
  { \CTEX@beginallalchar #1 \CTEX@endallalchar }
\cs_new_protected:Npn \CTEX@beginallalchar
  {
    \group_begin:
      \ctex_ltj_zero_globaldefs:
      \ltj@allalchar
  }
\cs_new_protected:Npn \CTEX@endallalchar
  { \group_end: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CTEX@chardef@text@cmd}
% 补丁 \tn{chardef@text@cmd}，应用于 \tn{DeclareTextSymbol}，使其定义的符号都是 ALchar。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@chardef@text@cmd #1
  {
    \cs_set_eq:NN \@ifdefinable \@@@@ifdefinable
    \tl_set:Nn \l_@@_cmd_tl {#1}
    \tex_afterassignment:D \@@_chardef_text_cmd:
    \tex_chardef:D #1
  }
\tl_new:N \l_@@_cmd_tl
\cs_new_protected:Npn \@@_chardef_text_cmd:
  { \exp_after:wN \@@_chardef_text_cmd_aux:N \l_@@_cmd_tl }
\cs_new_protected:Npn \@@_chardef_text_cmd_aux:N #1
  {
    \int_compare:nNnF {#1} &lt; { "80 }
      { \cs_set_protected:Npx #1 { \CTEX@alchar { \tex_Uchar:D #1 } } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CTEX@text@composite@x}
% \tn{@text@composite@x} 的重定义，应用于 \tn{DeclareUnicodeComposite} 等。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@text@composite@x #1#2
  {
    \CTEX@beginallalchar
      \cs_if_exist_use:NF #1 {#2}
    \CTEX@endallalchar
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CTEX@add@unicode@accent}
% \tn{add@unicode@accent} 的重定义，应用于 \tn{DeclareUnicodeAccent}。
%    \begin{macrocode}
\cs_new_protected:Npx \CTEX@add@unicode@accent #1#2
  {
    \CTEX@beginallalchar
      \exp_not:N \tl_if_blank:nTF {#2} { \tex_Uchar:D "A0 ~ } {#2}
      \exp_not:N \tex_Uchar:D \tex_numexpr:D #1 \scan_stop:
    \CTEX@endallalchar
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CTEX@patch@text@cmd}
% 单独补丁由 \tn{DeclareTextCommand} 定义的命令。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@patch@text@cmd #1
  {
    \exp_args:NNc \@@_patch_text_cmd:NN #1
      { \UnicodeEncodingName \token_to_str:N #1 }
  }
\cs_new_protected:Npn \@@_patch_text_cmd:NN #1#2
  {
    \cs_set_eq:NN \CTEX@textcmd #2
    \ctex_preto_cmd:NnnTF \CTEX@textcmd
      { \ExplSyntaxOff \makeatletter }
      { \CTEX@beginallalchar }
      {
        \ctex_appto_cmd:NnnTF \CTEX@textcmd
          { \ExplSyntaxOff \makeatletter }
          { \CTEX@endallalchar }
          { \cs_set_eq:NN #2 \CTEX@textcmd }
          { \ctex_patch_failure:N #1 }
      }
      { \ctex_patch_failure:N #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CTEX@patch@tunec}
% 重新载入 \tn{tunec.def}，使补丁生效。
%    \begin{macrocode}
\cs_new_protected:Npn \CTEX@patch@tunec
  {
    \cs_set_eq:NN \chardef@text@cmd   \CTEX@chardef@text@cmd
    \ctex_file_input:n { tuenc.def }
    \cs_set_eq:NN \@text@composite@x  \CTEX@text@composite@x
    \cs_set_eq:NN \add@unicode@accent \CTEX@add@unicode@accent
    \CTEX@patch@text@cmd \textasteriskcentered
  }
\@ifpackageloaded { xunicode }
  { }
  { \CTEX@patch@tunec }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.3}{2015/09/26}{更新 \pkg{unicode-math} 宏包补丁。}
%
% 在 \LaTeX{} 下，\pkg{LuaTeX-ja} 对 \pkg{fontspec}、\pkg{xunicode}、\pkg{unicode-math}
% 和 \pkg{listings} 打了补丁。其中前三个是把 \tn{char} 换成 \tn{ltjalchar}，确保
% 字符是 ALchar 类。我们这里用 \pkg{xunicode-addon} 来处理 \pkg{xunicode}。
%    \begin{macrocode}
\ctex_at_end_package:nn { xunicode }
  {
    \RequirePackage { xunicode-addon }
    \AtBeginUTFCommand { \CTEX@beginallalchar }
    \AtEndUTFCommand   { \CTEX@endallalchar }
  }
%    \end{macrocode}
%
% \changes{v2.4.2}{2016/05/15}{恢复 \pkg{luatexja} 对 \tn{emshape} 和
% \tn{eminnershape} 的重定义。}
% \changes{v2.4.3}{2016/08/26}{简化 \pkg{fontspec} 补丁。}
% \changes{v2.5}{2020/04/18}{删除 \pkg{fontspec} 补丁。}
%
% 对 \pkg{listings} 的补丁是让代码环境支持 JAchar 类。
%    \begin{macrocode}
\ctex_at_end_package:nn { listings }
  { \RequirePackage { lltjp-listings } }
%    \end{macrocode}
%
% \paragraph{\pkg{Lua} 函数}
%
% \changes{v2.5.8}{2021/11/29}{简化部分 \pkg{Lua} 函数。}
%
% 直接用 |token.set_lua| 定义，不是传统意义上的 \TeX \ 宏。
%    \begin{macrocode}
\group_begin:
\char_set_catcode_space:n { 32 }
\lua_now:e
  {
%    \end{macrocode}
% \begin{macro}{ctex.newluacmd}
% 定义新的 \pkg{Lua} 函数。
%    \begin{macrocode}
    ctex = ctex or { }
    local ctex = ctex
    local functions = lua.get_functions_table()
    local new_luafunction = luatexbase.new_luafunction
    local create, set_lua = token.create, token.set_lua
    local lua_cmds = {
      lua_call            = true ,
      lua_expandable_call = true ,
    }
    local newluacmd = function (name, func, ...)
      local tok = create(name)
      local id = lua_cmds[tok.cmdname] and tok.index
      local id = id or new_luafunction(name)
      set_lua(name, id, ...)
      functions[id] = func
    end
    ctex.newluacmd = newluacmd
%    \end{macrocode}
% \end{macro}
%    \begin{macrocode}
    local ltjfont = luatexja.jfont
    local getattribute = tex.getattribute
    local tex_set, sprint = tex.set, tex.sprint
    local scan_int, scan_arg = token.scan_int, token.scan_argument
%    \end{macrocode}
% \begin{macro}{\ctex_ltj_add_kyenc:n}
% 保存 jfont 的编码，用于判断。
%    \begin{macrocode}
    newluacmd("ctex_ltj_add_kyenc:n", ltjfont.add_kyenc_list, "global", "protected")
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ctex_ltj_is_kenc:n}
% 判断编码是否属于 jfont。
%    \begin{macrocode}
    newluacmd("ctex_ltj_is_kenc:n", ltjfont.is_kenc, "global")
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ctex_ltj_patch_external_font:n}
% 若对字体的定义完全相同，则它们有相同的 \texttt{font.id}。因此如果字形是由
% \textsf{NFSS} 的替换机制定义的，它们就有相同的 \texttt{font.id}。
% |print_aftl_address| 函数的定义是
% \begin{verbatim}
%   function luatexja.jfont.print_aftl_address()
%     return ';ltjaltfont' .. tostring(aftl_base):sub(8)
%   end
% \end{verbatim}
% 主要目的是，如果当前字形有替代字体，则往字形的定义中加入一些标志，确保
% \texttt{font.id} 唯一。
%    \begin{macrocode}
    newluacmd("ctex_ltj_patch_external_font:n", function ()
      local s = scan_arg()
      local is_braced, is_quoted
      if s:sub(1,1) == '{' and s:sub(-1)=='}' then
        is_braced = true; s = s:sub(2,-2)
      end
      if s:sub(1,1) == '"' and s:sub(-1) == '"' then
        is_quoted = true; s = s:sub(2,-2)
      end
      s = s .. ltjfont.print_aftl_address()
      if     is_braced then s = '{'..s..'}'
      elseif is_quoted then s = '"'..s..'"'
      end
      sprint(-2, s)
    end, "global")
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ctex_ltj_set_alt_font:nnnn}
% |#1| 和 |#2| 分别是字符区间的首末，|#3| 是基础字体，|#4| 是替代字体。
%    \begin{macrocode}
    newluacmd("ctex_ltj_set_alt_font:nnnn", function ()
      local b = tonumber(scan_arg())
      local e = tonumber(scan_arg())
      local alt  = scan_arg()
      local base = scan_arg()
      ltjfont.set_alt_font_latex(b, e, alt, base)
    end, "global", "protected")
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ctex_ltj_clear_alt_font:n}
% 清除 |#1| 的替代字体。
%    \begin{macrocode}
    newluacmd("ctex_ltj_clear_alt_font:n", function ()
      local base = scan_arg()
      ltjfont.clear_alt_font_latex(base)
    end, "global", "protected")
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ctex_ltj_pickup_alt_font:nn}
% 定义 |#1| 的替代字体，|#2| 是字体大小。\\
% 会在内部执行 \tn{ltj@pickup@altfont@auxy} 和 \tn{ltj@pickup@altfont@copy}。
%    \begin{macrocode}
    newluacmd("ctex_ltj_pickup_alt_font:nn", function ()
      local base = scan_arg()
      local size = scan_arg()
      ltjfont.output_alt_font_cmd("y", base)
      ltjfont.pickup_alt_font_a(size)
    end, "global", "protected")
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_pickup_alt_font:Nn}
% |#1| 是 \texttt{font.id}，|#2| 是字体名称。
% 在 \tn{ltj@pickup@altfont@copy} 之中使用。
%    \begin{macrocode}
    newluacmd("@@_pickup_alt_font:Nn", function ()
      local num  = scan_int()
      local base = scan_arg()
      ltjfont.pickup_alt_font_b(num, base)
    end, "global", "protected")
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_if_alt_set:nT}
% 判断是否存在替代字体。会设置变量 |aftl_base| 和返回 \tn{@firstofone} 或 \tn{@gobble}。
%    \begin{macrocode}
    newluacmd("@@_if_alt_set:nT", ltjfont.does_alt_set, "global")
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\ctex_ltj_zero_globaldefs:}
% 设置 \tn{globaldefs} 为 $0$，避免全局设置，应当在分组中使用。
% 这里通过 Lua 设置，可以不受外部 \TeX\ 环境中的 \tn{globaldefs} 的影响。
%    \begin{macrocode}
    newluacmd("ctex_ltj_zero_globaldefs:", function ()
      tex_set("globaldefs", 0)
    end, "global", "protected")
  }
\group_end:
%    \end{macrocode}
% \end{macro}
%
% \paragraph{字体切换方式}
%
% \begin{macro}[int]{\ctex_ltj_select_font:,\CJK@family}
% \tn{CJK@family} 保存的是当前 CJK 实际的字体族名，如果为空表示没有设置过字体。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_select_font:
  {
    \group_begin: \exp_args:NNc \group_end:
    \cs_if_exist_use:NF { \l_@@_current_font_tl }
      { \tl_if_empty:NF \CJK@family { \@@_select_font_aux: } }
  }
\tl_new:N \CJK@family
\tl_new:N \l_@@_current_font_tl
\tl_set:Nn \l_@@_current_font_tl
  { \CJK@encoding / \CJK@family / \f@series / \f@shape / \f@size }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.8}{2021/11/18}{兼容 \pkg{microtype}。}
%
% \begin{macro}{\@@_select_font_aux:}
% 使用 \tn{pickup@font} 取得字体名称前，总需要先设置 \tn{font@name}。在这里将
% \tn{f@family} 换成 CJK 字体族，并确保编码正确。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_select_font_aux:
  {
    \group_begin:
      \tl_set_eq:NN \f@encoding \CJK@encoding
      \tl_set_eq:NN \f@family \CJK@family
      \cs_set_eq:NN \pickup@font \ctex_ltj_pickup_font:
      \@@_push_fontname:n { \curr@fontshape / \f@size }
      \ctex_ltj_pickup_font:
    \group_end:
    \font@name
    \@@_pop_fontname:
%    \end{macrocode}
% 当字形未定义的时候，\textsf{NFSS} 就会启动替换机制（\tn{wrong@fontshape}）。
% 第一次启动后，\cs{l_@@_current_font_tl} 还是没有定义。为此，我们再次选择字体，
% 确保它有定义和指向正确的 \texttt{font.id}。这对 \opt{AlternateFont} 的设置
% 特别重要。
%    \begin{macrocode}
    \cs_if_exist:cF { \l_@@_current_font_tl }
      { \@@_select_font_aux: }
  }
\cs_new_protected:Npn \@@_push_fontname:n #1
  {
    \seq_gpush:No \g_@@_fontname_seq { \font@name }
    \tl_gset:Nx \font@name { \exp_not:c {#1} }
  }
\cs_new_protected:Npn \@@_pop_fontname:
  {
    \seq_gpop:NNT \g_@@_fontname_seq \l_@@_tmp_tl
      { \tl_gset_eq:NN \font@name \l_@@_tmp_tl }
  }
\seq_new:N \g_@@_fontname_seq
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_pickup_font:}
% 替换 \tn{define@newfont} 内部调用的 \tn{extract@font} 和 \tn{do@subst@correction}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_pickup_font:
  {
    \exp_after:wN \cs_if_exist:NF \font@name
      {
        \group_begin:
          \cs_set_eq:NN \extract@font \ctex_ltj_extract_font:
          \cs_set_eq:NN \do@subst@correction \ctex_ltj_subst_font:
          \define@newfont
        \group_end:
      }
  }
\cs_new_eq:NN \pickup@jfont \ctex_ltj_pickup_font:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_extract_font:}
% \pkg{LuaTeX-ja} 的 \tn{globaljfont} 在 \pkg{luatexja-core} 中定义：
% \begin{verbatim}
%   %%%%%%%% \jfont\CS={...:...;jfm=metric;...}, \globaljfont
%   \protected\def\jfont#1{%
%     \afterassignment\ltj@@jfont
%     \directlua{luatexja.jfont.jfontdefX
%       (false, 'yoko','\luatexluaescapestring{\noexpand#1}')}}
%   \protected\def\globaljfont#1{%
%     \afterassignment\ltj@@jfont
%     \directlua{luatexja.jfont.jfontdefX
%       (true,  'yoko','\luatexluaescapestring{\noexpand#1}')}}
%   \newluafunction\ltj@@jfont@inner
%   \directlua{
%     local t = lua.get_functions_table()
%     t[\the\ltj@@jfont@inner] = luatexja.jfont.jfontdefY
%   }
%   \def\ltj@@jfont{\luafunction\ltj@@jfont@inner}
% \end{verbatim}
% \texttt{jfontdefX} 函数的作用是把 \tn{CS} 定义为其后的字体，\texttt{jfontdefY}
% 的作用是更新 \texttt{JFM} 和记录相关字体信息。最后的工作是：
% \begin{verbatim}
%   tex.sprint(cat_lp, global_flag, '\\protected\\expandafter\\def\\csname ',
%     (cstemp==' ') and '\\space' or cstemp, '\\endcsname{\\ltj@cur'..
%     (jfm_dir == 'yoko' and 'j' or 't') .. 'fnt', fn, '\\relax}')
% \end{verbatim}
% \tn{CS} 的作用就是把 \tn{ltj@curjfnt} 设置为刚才定义的字体的 \texttt{font.id}。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_extract_font:
  {
    \get@external@font
    \ctex_ltj_if_alternate_shape_exist:nT { \curr@fontshape }
      {
        \tl_set:Nx \external@font
          { \exp_after:wN \@@_patch_external_font:w \external@font }
      }
    \exp_after:wN \globaljfont \font@name \external@font \scan_stop:
%    \end{macrocode}
% 这里 \tn{font@name} 不会直接改变当前字体，而 \tn{DeclareFontFamily} 和
% \tn{DeclareFontShape} 的最后一个参数通常要使用 \tn{font} 来引用当前字体。
% 为此，我们在分组内启用之前定义的字体，以便能得到正确的 \tn{font}。对字体参数的
% 赋值总是全局的，不会受到分组的影响。
%    \begin{macrocode}
    \font@name
    \ctex_ltj_use_jfont:
    \use:c { \f@encoding + \f@family }
    \use:c { \curr@fontshape }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ctex_ltj_use_jfont:}
% 使用 jfont，确保当前的 \tn{font} 是 jfont。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_use_jfont:
  { \tex_setfontid:D \ltj@curjfnt }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_subst_font:}
% \tn{do@subst@correction} 在设置通过 \texttt{sub} 或者 \texttt{ssub} 函数定义的
% 字体时会用到。如果没有设置 \opt{SlantedFont}，\pkg{fontspec} 会设置
% \tn{itdefault} 作为 \tn{sldefault} 的替代字形，因而会用到这个函数。它的本来定义是：
% \begin{verbatim}
%   \def\do@subst@correction{%
%       \xdef\subst@correction{%
%          \font@name
%          \global\expandafter\font
%            \csname \curr@fontshape/\f@size\endcsname
%            \noexpand\fontname\font
%           \relax}%
%       \aftergroup\subst@correction
%   }
% \end{verbatim}
% 我们在这里不需要定义新字体，而是设置对应字体的命令。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \ctex_ltj_subst_font:
  {
    \ctex_ltj_if_alternate_shape_exist:nF { \curr@fontshape }
      {
        \group_begin:
        \tl_set_eq:NN \CJK@family \f@family
        \cs_if_exist:cF { \l_@@_current_font_tl  }
          {
            \cs_gset_protected_nopar:Npx \subst@correction
              {
                \cs_new_eq:NN
                  \exp_not:c { \l_@@_current_font_tl }
                  \font@name
              }
            \group_insert_after:N \group_insert_after:N
            \group_insert_after:N \subst@correction
          }
        \group_end:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int,TF]{\ctex_ltj_if_alternate_shape_exist:n}
% 即 \pkg{LuaTeX-ja} 中的 \tn{ltj@@does@alt@set}，判断是否存在替代字体。
%    \begin{macrocode}
\prg_new_conditional:Npnn \ctex_ltj_if_alternate_shape_exist:n #1 { T , F , TF }
  {
    \@@_if_alt_set:nT {#1} { \prg_return_true: \use_none:n }
    \prg_return_false:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_patch_external_font:w}
%    \begin{macrocode}
\cs_new:Npn \@@_patch_external_font:w #1 ~ at
  { \ctex_ltj_patch_external_font:n {#1} ~ at }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_select_alternate_font:}
% 在 \tn{selectfont} 中更新替代字体。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_select_alternate_font:
  {
    \ctex_ltj_if_alternate_shape_exist:nT { \l_@@_current_shape_tl }
      {
        \ctex_ltj_pickup_alt_font:nn
          { \l_@@_current_shape_tl } { \f@size }
      }
  }
\tl_new:N \l_@@_current_shape_tl
\tl_set:Nn \l_@@_current_shape_tl
  { \CJK@encoding / \CJK@family / \f@series / \f@shape }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ltj@pickup@altfont@auxy}
% 被用在函数 |output_alt_font_cmd| 中，作用是定义替代字体。
%    \begin{macrocode}
\cs_new_protected:Npn \ltj@pickup@altfont@auxy #1
  {
    \cs_if_exist:cF { #1/\f@size }
      {
        \group_begin:
          \use:e { \exp_not:N \split@name #1 / \f@size } \@nil
          \@@_push_fontname:n { \curr@fontshape / \f@size }
          \ctex_ltj_pickup_font:
        \group_end:
        \@@_pop_fontname:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ltj@pickup@altfont@copy}
% 被用在函数 |pickup_alt_font_a| 中。\tn{ltj@@getjfontnumber} 的作用是将字体命令
% |#1| 对应的 \texttt{font.id} 保存到 \tn{ltj@tempcntc} 中。
%    \begin{macrocode}
\cs_new_protected:Npn \ltj@pickup@altfont@copy #1#2
  {
    \ltj@@@@getjfontnumber #1
    \@@_pickup_alt_font:Nn \ltj@tempcntc {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% \paragraph{数学字体族}
%
% 以下内容来自 \file{lltjfont.sty}，目的是让汉字可以在数学环境中直接使用。
%
% \begin{macro}[int]{\ctex_ltj_if_jfont:nTF}
% 参数 |#1| 是一个 \LaTeXe{} 编码名称或者字体命令。\LaTeXe{} 字体命令的一般形式是：
% \begin{quote}\ttfamily\small
%   \textbackslash\meta{encoding}/\meta{family}/\meta{series}/\meta{shape}
% \end{quote}
% 通过截取名字中的 \meta{encoding} 来判断是否是 jfont。
% 最后会设置 \tn{ifin@} 为对应的 \tn{iftrue} 或者 \tn{iffalse}。
%    \begin{macrocode}
\cs_new:Npn \ctex_ltj_if_jfont:nTF #1
  {
    \ctex_ltj_is_kenc:n { \@@_ltj_if_jfont:w #1 / \q_stop }
    \legacy_if:nTF { in@ }
  }
\cs_new:Npn \@@_ltj_if_jfont:w #1 / #2 \q_stop
  {#1}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_if_jfont_math:NTF}
% |#1| 是一个形式为 |\M@|\meta{encoding} 的命令，它由 \tn{DeclareFontEncoding} 的
% 第三个参数来定义。
%    \begin{macrocode}
\cs_new:Npn \ctex_ltj_if_jfont_math:NTF #1
  { \exp_after:wN \@@_if_jfont_math:w \token_to_str:N #1 \q_stop }
\group_begin:
  \char_set_catcode_other:N M
  \cs_new:Npn \@@_if_jfont_math:w #1 M #2#3 \q_stop
    { \ctex_ltj_if_jfont:nTF {#3} }
\group_end:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\getanddefine@fonts,\ctex_ltj_get_and_define_fonts:nN}
% 在使用的场合，\tn{escapechar} 已经被设置成 $-1$，使用 \cs{token_to_str:N} 就
% 可以得到名字，不必使用 \cs{cs_to_str:N}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_get_and_define_fonts:nN #1#2
  {
    \exp_args:No \ctex_ltj_if_jfont:nTF { \token_to_str:N #2 }
      { \ctex_ltj_get_and_define_fonts_ja:nN }
      { \ctex_ltj_get_and_define_fonts_al:nN }
      {#1} #2
  }
\cs_new_eq:NN \ctex_ltj_get_and_define_fonts_al:nN \getanddefine@fonts
\cs_set_eq:NN \getanddefine@fonts \ctex_ltj_get_and_define_fonts:nN
\cs_new_protected:Npn \ctex_ltj_get_and_define_fonts_ja:nN #1#2
  {
    \tl_gset:Nx \font@name { \use:c { \token_to_str:N #2 / \tf@size } }
    \ctex_ltj_pickup_font: \tl_set_eq:NN \textfont@name \font@name
    \tl_gset:Nx \font@name { \use:c { \token_to_str:N #2 / \sf@size } }
    \ctex_ltj_pickup_font: \tl_set_eq:NN \scriptfont@name \font@name
    \tl_gset:Nx \font@name { \use:c { \token_to_str:N #2 / \ssf@size } }
    \ctex_ltj_pickup_font:
    \tl_put_right:Nx \math@fonts
      {
        \ltj@setpar@global
        \ltj@@@@set@stackfont #1 , \textfont@name   \c_colon_str { MJT }
        \ltj@@@@set@stackfont #1 , \scriptfont@name \c_colon_str { MJS }
        \ltj@@@@set@stackfont #1 , \font@name       \c_colon_str { MJSS }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\use@mathgroup,\ctex_ltj_use_math_group:Nn}
% 在使用 \pkg{unicode-math} 宏包时，\cs{ctex_ltj_math_group_hook:} 将被重定义。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_use_math_group:Nn #1#2
  {
    \mode_if_math:T
      {
        \math@bgroup
          \cs_if_eq:cNF { M@ \f@encoding } #1 {#1}
          \ctex_ltj_math_group_hook:
          \ctex_ltj_if_jfont_math:NTF #1
            { \jfam } { \mathgroup } #2 \scan_stop:
        \math@egroup
      }
  }
\cs_new_eq:NN \ctex_ltj_math_group_hook: \prg_do_nothing:
\cs_set_eq:NN \use@mathgroup \ctex_ltj_use_math_group:Nn
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.4.3}{2016/08/25}{更新 \pkg{unicode-math} 补丁。}
% \changes{v2.4.9}{2017/02/27}{调整 \pkg{unicode-math} 补丁的代码顺序。}
% 对 \pkg{unicode-math} 的补丁主要是将 \file{unicode-math-table.tex} 中的数学符号设置为
% \pkg{luatexja} 中的数学字母。
% 本段代码应放在 \cs{ctex_ltj_math_group_hook:} 的定义之后，避免因宏包载入顺序而造成的编译错误。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_set_math_letter:NN #1#2
  {
    \group_begin:
      \cs_set_protected:Npn #1 ##1##2##3
        { \ltjsetmathletter { ##1 } }
      #2
    \group_end:
  }
\ctex_at_end_package:nn { unicode-math }
  {
    \cs_if_exist:NTF \um_input_math_symbol_table:
      {
        \ctex_ltj_set_math_letter:NN
          \um_sym:nnn
          \um_input_math_symbol_table:
      }
      {
        \cs_set_eq:NN \use@mathgroup \ctex_ltj_use_math_group:Nn
        \cs_set_protected:Npn \ctex_ltj_math_group_hook:
          { \__um_switchto_literal: }
        \ctex_ltj_set_math_letter:NN
          \__um_sym:nnn
          \__um_input_math_symbol_table:
      }
  }
%    \end{macrocode}
%
% \paragraph{字体族的定义与使用}
%
% \changes{v2.5.9}{2022/05/26}{依赖 \pkg{chinese-jfm} 宏包。}
%
% \begin{macro}[int]{\ctex_set_jfm:n}
% \begin{variable}{\l_@@_jfm_tl, \l_@@_redirect_jfm_prop}
% 设置 \texttt{JFM}，需要进行一些重定向操作。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_set_jfm:n #1
  {
    \prop_get:NnNF \l_@@_redirect_jfm_prop {#1} \l_@@_jfm_tl
      { \tl_set:Nn \l_@@_jfm_tl {#1} }
  }
\cs_generate_variant:Nn \ctex_set_jfm:n { o }
\prop_new:N \l_@@_redirect_jfm_prop
\prop_set_from_keyval:Nn \l_@@_redirect_jfm_prop
  {
    plain    = mono ,
    quanjiao = zh_CN / quanjiao ,
    banjiao  = zh_CN / banjiao ,
    kaiming  = zh_CN / kaiming
  }
\keys_define:nn { ctex_ltj / fontspec }
  {
    JFM           .code:n = \ctex_set_jfm:n {#1} ,
    JFM .value_required:n = true
  }
\tl_new:N \l_@@_jfm_tl
\ctex_set_jfm:o { \l__ctex_punct_tl }
%    \end{macrocode}
% \end{variable}
% \end{macro}
%
% \begin{macro}[int]{\CJK@encoding}
% 在 \LaTeX 下，\pkg{LuaTeX-ja} 依赖字体编码来实现特殊设置。例如上述的
% \cs{ctex_ltj_if_jfont:nTF} 就是通过判断编码来实现的，它在设置数学字体时会用到。所以
% 不应该与西文共用 \texttt{EU2}。定义字体族 song 为 \tn{CJK@encoding} 的默认替换
% 字体。下划线 |_| 不在 \tn{nfss@catcodes} 里，可以放心使用。
%    \begin{macrocode}
\tl_const:Nn \CJK@encoding { LTJY3 }
\DeclareFontEncoding { \CJK@encoding } { } { }
\use:e
  {
    \exp_not:N \DeclareFontSubstitution
      { \CJK@encoding } { song } { \mddefault } { \shapedefault }
  }
\ctex_ltj_add_kyenc:n { \CJK@encoding }
\DeclareFontFamily { \CJK@encoding } { song } { }
\DeclareFontShape { \CJK@encoding } { song } { \mddefault } { \shapedefault }
  { &lt;-&gt; psft:SimSun:cid=Adobe-GB1-5;jfm=\l_@@_jfm_tl } { }
\DeclareFontShape { \CJK@encoding } { song } { \bfdefault } { \shapedefault }
  { &lt;-&gt; psft:SimHei:cid=Adobe-GB1-5;jfm=\l_@@_jfm_tl } { }
\tl_const:Nn \c_@@_math_tl { CJKmath }
\DeclareSymbolFont { \c_@@_math_tl }
  { \CJK@encoding } { song } { \mddefault } { \shapedefault }
\SetSymbolFont { \c_@@_math_tl } { bold }
  { \CJK@encoding } { song } { \bfdefault } { \shapedefault }
\int_const:Nn \c_@@_math_fam_int { \use:c { sym \c_@@_math_tl } }
\jfam \c_@@_math_fam_int
%    \end{macrocode}
% \end{macro}
%
% 这是 \pkg{luatexja-fontspec} 中新增的一些字体选项。
%    \begin{macrocode}
\newfontfeature { CID }     {    cid = #1 }
\newfontfeature { JFM }     {    jfm = #1 }
\newfontfeature { JFM-var } { jfmvar = #1 }
%    \end{macrocode}
%
% 在新版本的 \pkg{fontspec} 中，\cs{__fontspec_fontname_wrap:n} 变成了私有函数。
%    \begin{macrocode}
\keys_define:nn { fontspec-preparse-external }
  {
    NoEmbed .code:n =
      { \cs_set_eq:NN \__fontspec_fontname_wrap:n \@@_noembed_wrap:n }
  }
\cs_new:Npn \@@_noembed_wrap:n #1 { psft: #1 }
%    \end{macrocode}
%
% \begin{macro}[int]{\ctex_ltj_set_family:nnn}
% 将自定义的字体族名与 \pkg{fontspec} 实际设置的名字对应起来。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_set_family:nnn #1#2#3
  {
    \group_begin:
    \clist_clear:N \l_@@_char_range_clist
    \prop_clear:N \l_@@_alternate_prop
    \tl_set:Nn \l_@@_base_CJKfamily_tl {#1}
    \keys_set_known:nnN { ctex_ltj / fontspec } {#2} \l_@@_tmp_tl
    \clist_set:No \l_@@_font_options_clist { \l_@@_tmp_tl }
    \ctex_ltj_set_alternate_family:nnF {#1} {#3}
      {
        \prop_gput:Nnn \g_@@_family_font_name_prop {#1} {#3}
        \prop_gput:Nno \g_@@_family_font_options_prop
          {#1} { \l_@@_font_options_clist }
        \@@_update_family_uid:N \l_@@_font_options_clist
        \@@_use_global_options:N \l_@@_font_options_clist
        \@@_gset_family_cs:nn {#1} {#3}
      }
    \group_end:
  }
\tl_new:N \l_@@_base_CJKfamily_tl
\clist_new:N \l_@@_font_options_clist
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_use_global_options:N}
% 应用默认字体选项，并总是设置 \opt{JFM} 和 \opt{NFSSEncoding} 。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_use_global_options:N #1
  {
    \clist_concat:NNN #1 \g_@@_default_features_clist #1
    \clist_put_left:Nx #1
      { NFSSEncoding = \CJK@encoding , JFM = \l_@@_jfm_tl }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}
%  {\g_@@_family_name_prop,\g_@@_family_font_name_prop,\g_@@_family_font_options_prop}
% 分别保存 \pkg{fontspec} 设置的字体族名、字体名称和字体选项。
%    \begin{macrocode}
\prop_new:N \g_@@_family_name_prop
\prop_new:N \g_@@_family_font_name_prop
\prop_new:N \g_@@_family_font_options_prop
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_check_family:n}
% 删除重复的定义，清除替代字体的先前设置。
%   \begin{macrocode}
\cs_new_protected:Npn \@@_check_family:n #1
  {
    \prop_gpop:NnNT \g_@@_family_font_name_prop {#1} \l_@@_tmp_tl
      {
        \cs_undefine:c { \@@_family_csname:n {#1} }
        \cs_undefine:c { \@@_alternate_cs:n {#1} }
        \prop_gpop:NnNT \g_@@_family_name_prop {#1} \l_@@_base_family_tl
          {
            \use:c { \@@_alternate_cs:n { clear / #1 } }
            \cs_undefine:c { \@@_alternate_cs:n { clear / #1 } }
            \cs_undefine:c { \@@_alternate_cs:n { reset / #1 } }
            \prop_gremove:Nn \g_@@_reset_alternate_prop {#1}
          }
        \msg_warning:nnxx { ctex } { redefine-family } {#1} { \l_@@_tmp_tl }
      }
  }
\tl_new:N \l_@@_tmp_tl
\msg_new:nnn { ctex } { redefine-family }
  { Redefining~CJKfamily~`\@@_msg_family_map:n {#1}'~(#2). }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_gset_family_cs:nn}
% 在设置字体时，实际上并不是马上就定义。而是只保存相关参数，在通过 \tn{CJKfamily}
% 第一次使用时才定义。需要注意将编码改为 \tn{CJK@encoding}。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_gset_family_cs:nn #1#2
  {
    \cs_gset_protected:cpx { \@@_family_csname:n {#1} }
      {
        \group_begin:
        \exp_not:n { \cs_set_eq:NN \CJKfamily \use_none:n }
        \exp_not:n { \fontspec_gset_family:Nnn \g_@@_fontspec_family_tl }
          { \exp_not:o { \l_@@_font_options_clist } } {#2}
        \prop_gput:Nno \exp_not:N \g_@@_family_name_prop {#1}
          { \exp_not:N \g_@@_fontspec_family_tl }
        \@@_set_alternate_family:n {#1}
        \group_end:
      }
  }
\tl_new:N \l_@@_base_family_tl
\tl_new:N \g_@@_fontspec_family_tl
\cs_new:Npn \@@_family_csname:n #1 { ctex_ltj/family/#1 }
\cs_new_protected:Npn \@@_set_alternate_family:n #1
  {
    \tl_set:Nn \l_@@_base_CJKfamily_tl {#1}
    \tl_set_eq:NN \l_@@_base_family_tl \g_@@_fontspec_family_tl
    \cs_if_exist_use:c { \@@_alternate_cs:n { reset / #1 } }
    \cs_if_exist_use:c { \@@_alternate_cs:n {#1} }
  }
\cs_new:Npn \@@_alternate_cs:n #1 { ctex_ltj/alternate_family/#1 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\CJKfamily}
% 切换字体。
%    \begin{macrocode}
\NewDocumentCommand \CJKfamily { m }
  { \ctex_ltj_switch_family:x {#1} \tex_ignorespaces:D }
\cs_new_protected:Npn \ctex_ltj_switch_family:n #1
  {
    \ctex_ltj_family_if_exist:nNTF {#1} \CJK@family
      {
        \tl_set:Nn \l_ctex_ltj_family_tl {#1}
        \selectfont
      }
      { \@@_family_unknown_warning:n {#1} }
  }
\tl_new:N \l_ctex_ltj_family_tl
\cs_generate_variant:Nn \ctex_ltj_switch_family:n { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int,TF]{\ctex_ltj_family_if_exist:nN}
% 判断 CJK 字体族 |#1| 是否存在，若存在则把实际族名保存到 |#2| 中。
%    \begin{macrocode}
\prg_new_protected_conditional:Npnn \ctex_ltj_family_if_exist:nN #1#2 { T , F , TF }
  {
    \prop_get:NnNTF \g_@@_family_name_prop {#1} #2
      { \prg_return_true: }
      {
        \cs_if_exist_use:cTF { \@@_family_csname:n {#1} }
          {
            \tl_set_eq:NN #2 \g_@@_fontspec_family_tl
            \prg_return_true:
          }
          { \prg_return_false: }
      }
  }
\prg_generate_conditional_variant:Nnn \ctex_ltj_family_if_exist:nN { x } { T , F , TF }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_family_unknown_warning:n}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_family_unknown_warning:n #1
  {
    \prop_if_empty:NF \g_@@_family_font_name_prop
      {
        \seq_if_in:NnF \g_@@_unknown_family_seq {#1}
          {
            \seq_gput_right:Nn \g_@@_unknown_family_seq {#1}
            \msg_warning:nnn { ctex } { family-unknown } {#1}
          }
      }
  }
\seq_new:N \g_@@_unknown_family_seq
\msg_new:nnn { ctex } { family-unknown }
  {
    Unknown~CJK~family~`\@@_msg_family_map:n {#1}'~is~being~ignored.\\
    Try~to~use~`\@@_msg_def_family_map:n {#1}'~to~define~it.
  }
\cs_new:Npn \@@_msg_def_family_map:n #1
  {
    \str_case_e:nnF {#1}
      {
        \CJKrmdefault { \token_to_str:N \setCJKmainfont }
        \CJKsfdefault { \token_to_str:N \setCJKsansfont }
        \CJKttdefault { \token_to_str:N \setCJKmonofont }
      }
      { \token_to_str:N \setCJKfamilyfont \{ #1 \} }
    [...]\{...\}
  }
\cs_new:Npn \@@_msg_family_map:n #1
  {
    \str_case_e:nnF {#1}
      {
        \CJKrmdefault { \token_to_str:N \CJKrmdefault }
        \CJKsfdefault { \token_to_str:N \CJKsfdefault }
        \CJKttdefault { \token_to_str:N \CJKttdefault }
      }
      {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_fontspec:nn}
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_fontspec:nn #1#2
  {
    \prop_get:NnNTF \g_@@_fontspec_prop
      { CJKfontspec/#1/#2/id } \l_ctex_ltj_family_tl
      { \ctex_ltj_switch_family:x { \l_ctex_ltj_family_tl } }
      {
        \int_gincr:N \g_@@_family_int
        \@@_fontspec:enn
          { CJKfontspec ( \int_use:N \g_@@_family_int ) }
          {#1} {#2}
      }
  }
\cs_new_protected:Npn \ctex_ltj_fontspec:ee #1#2
  { \use:e { \ctex_ltj_fontspec:nn {#1} {#2} } }
\cs_new_protected:Npn \@@_fontspec:nnn #1#2#3
  {
    \bool_if:NT \l_@@_add_alternate_bool
      {
        \cs_if_free:cF
          { \@@_alternate_cs:n { reset / \l_ctex_ltj_family_tl } }
          {
            \cs_gset_eq:cc
              { \@@_alternate_cs:n { reset / #1 } }
              { \@@_alternate_cs:n { reset / \l_ctex_ltj_family_tl } }
            \cs_gset_eq:cc
              { \@@_alternate_cs:n { clear / #1 } }
              { \@@_alternate_cs:n { clear / \l_ctex_ltj_family_tl } }
          }
        \bool_set_false:N \l_@@_add_alternate_bool
      }
    \prop_gput:Nnn \g_@@_fontspec_prop { CJKfontspec/#2/#3/id } {#1}
    \ctex_ltj_set_family:nnn {#1} {#2} {#3}
    \ctex_ltj_switch_family:n {#1}
  }
\cs_generate_variant:Nn \@@_fontspec:nnn { e }
\prop_new:N \g_@@_fontspec_prop
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]
% {\ctex_ltj_add_font_features:n,\ctex_ltj_add_font_features:nn}
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_add_font_features:n #1
  { \ctex_ltj_add_font_features:xn { \l_ctex_ltj_family_tl } {#1} }
\cs_new_protected:Npn \ctex_ltj_add_font_features:nn #1#2
  {
    \prop_get:NnNTF \g_@@_family_font_name_prop
      {#1} \l_@@_tmp_tl
      {
        \prop_get:NnN \g_@@_family_font_options_prop
          {#1} \l_@@_font_options_clist
        \clist_put_right:Nn \l_@@_font_options_clist {#2}
        \bool_set_true:N \l_@@_add_alternate_bool
        \ctex_ltj_fontspec:ee
          { \exp_not:o { \l_@@_font_options_clist } }
          { \exp_not:o { \l_@@_tmp_tl } }
      }
      { \msg_warning:nn { ctex } { addCJKfontfeature-ignored } }
  }
\bool_new:N \l_@@_add_alternate_bool
\cs_generate_variant:Nn \ctex_ltj_add_font_features:n  { x }
\cs_generate_variant:Nn \ctex_ltj_add_font_features:nn { x }
\msg_new:nnn { ctex } { addCJKfontfeature-ignored }
  {
    \token_to_str:N \addCJKfontfeature (s)~ignored.\\
    It~cannot~be~used~with~a~font~that~wasn't~selected~by~ctex.
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_pass_args:nnnn}
% 为了支持字体属性可选项在前在后两种语法，给出两个辅助工具，自带展开功能。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_pass_args:nnnn #1#2#3#4
  {
    \tl_if_novalue:nTF {#2}
      { \@@_post_arg:w {#1} {#3} {#4} }
      {
        \use:e { #1 {#2} {#3} }
        #4
      }
  }
\NewDocumentCommand \@@_post_arg:w { m m m O { } }
  {
    \use:e { #1 {#4} {#2} }
    #3
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.4.6}{2016/11/20}{支持字体属性可选项在后的新语法。}
%
% \begin{macro}[int]
% {\setCJKfamilyfont,\newCJKfontfamily,\CJKfontspec,\addCJKfontfeatures}
%    \begin{macrocode}
\NewDocumentCommand \setCJKfamilyfont { m o m }
  {
    \@@_pass_args:nnnn
      { \ctex_ltj_set_family:nnn {#1} } {#2} {#3}
      { }
  }
\NewDocumentCommand \newCJKfontfamily { o m o m }
  {
    \tl_set:Nx \l_@@_tmp_tl
      { \tl_if_novalue:nTF {#1} { \cs_to_str:N #2 } {#1} }
    \cs_new_protected:Npx #2
      { \ctex_ltj_switch_family:n { \l_@@_tmp_tl } }
    \@@_pass_args:nnnn
      { \ctex_ltj_set_family:nnn { \l_@@_tmp_tl } } {#3} {#4}
      { }
  }
\NewDocumentCommand \CJKfontspec { o m }
  {
    \@@_pass_args:nnnn
      { \ctex_ltj_fontspec:nn } {#1} {#2}
      { \tex_ignorespaces:D }
  }
\NewDocumentCommand \addCJKfontfeatures { m }
  {
    \ctex_ltj_add_font_features:x {#1}
    \tex_ignorespaces:D
  }
\cs_new_eq:NN \addCJKfontfeature \addCJKfontfeatures
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]
% {\setCJKmainfont,\setCJKsansfont,\setCJKmonofont,
%  \setCJKmathfont,\defaultCJKfontfeatures}
%    \begin{macrocode}
\NewDocumentCommand \setCJKmainfont { o m }
  {
    \@@_pass_args:nnnn
      { \ctex_ltj_set_family:nnn { \CJKrmdefault } } {#1} {#2}
      { \normalfont }
  }
\cs_new_eq:NN \setCJKromanfont \setCJKmainfont
\NewDocumentCommand \setCJKsansfont { o m }
  {
    \@@_pass_args:nnnn
      { \ctex_ltj_set_family:nnn { \CJKsfdefault } } {#1} {#2}
      { \normalfont }
  }
\NewDocumentCommand \setCJKmonofont { o m }
  {
    \@@_pass_args:nnnn
      { \ctex_ltj_set_family:nnn { \CJKttdefault } } {#1} {#2}
      { \normalfont }
  }
\NewDocumentCommand \setCJKmathfont { o m }
  {
    \@@_pass_args:nnnn
      { \ctex_ltj_set_family:nnn { \c_@@_math_tl } } {#1} {#2}
      { }
  }
\NewDocumentCommand \defaultCJKfontfeatures { m }
  { \clist_gset:Nn \g_@@_default_features_clist {#1} }
\clist_new:N \g_@@_default_features_clist
\@onlypreamble \setCJKmainfont
\@onlypreamble \setCJKsansfont
\@onlypreamble \setCJKmonofont
\@onlypreamble \setCJKmathfont
\@onlypreamble \setCJKromanfont
\@onlypreamble \defaultCJKfontfeatures
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.4.8}{2017/02/23}
%   {解决与 \pkg{fontspec} 2017/01/24 v2.5d 的字体族匹配兼容问题。}
%
% \begin{macro}[int]{\ctex_ltj_ensure_default_family:}
% 在导言区结束确认 \tn{CJKfamilydefault} 确实存在。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_ensure_default_family:
  {
    \prop_if_empty:NF \g_@@_family_font_name_prop
      {
        \ctex_ltj_family_if_exist:xNF { \CJKfamilydefault } \l_@@_tmp_tl
          {
            \str_if_eq:eeTF { \CJKfamilydefault } { \CJKrmdefault }
              { \use:n }
              {
                \ctex_ltj_family_if_exist:xNTF { \CJKrmdefault } \l_@@_tmp_tl
                  { \tl_gset:Nn \CJKfamilydefault { \CJKrmdefault } \use_none:n }
                  { \use:n }
              }
              {
                \prop_map_inline:Nn \g_@@_family_font_name_prop
                  {
                    \prop_map_break:n
                      { \tl_gset_rescan:Nnn \CJKfamilydefault { } { ##1 } }
                  }
              }
          }
        \normalfont
        \ctex_ltj_update_mathfont:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_update_mathfont:}
% 更新数学字体为实际的字体。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_update_mathfont:
  {
    \ctex_ltj_family_if_exist:xNTF { \c_@@_math_tl } \l_@@_tmp_tl
      { \ctex_ltj_update_mathfont:n { \l_@@_tmp_tl } }
      {
        \ctex_ltj_family_if_exist:xNT { \CJKfamilydefault } \l_@@_tmp_tl
          { \ctex_ltj_update_mathfont:n { \l_@@_tmp_tl } }
      }
  }
\cs_new_protected:Npn \ctex_ltj_update_mathfont:n #1
  {
    \tl_const:Nx \c_@@_math_family_tl {#1}
    \DeclareSymbolFont { \c_@@_math_tl } { \CJK@encoding }
      { \c_@@_math_family_tl } { \mddefault } { \shapedefault }
    \cs_if_free:cTF
      { \CJK@encoding/\c_@@_math_family_tl/\bfdefault/\shapedefault }
      {
        \SetSymbolFont { \c_@@_math_tl } { bold } { \CJK@encoding }
          { \c_@@_math_family_tl } { \mddefault } { \shapedefault }
      }
      {
        \SetSymbolFont { \c_@@_math_tl } { bold } { \CJK@encoding }
          { \c_@@_math_family_tl } { \bfdefault } { \shapedefault }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \paragraph{替代字体的设置}
%
% \changes{v2.5}{2020/04/30}{重构字体选项 \opt{AlternateFont}。}
%
% \begin{macro}{AlternateFont,CharRange}
% 设置替代字体的选项。
%    \begin{macrocode}
\keys_define:nn { ctex_ltj / fontspec }
  {
    AlternateFont  .code:n = \ctex_ltj_set_alternate_prop:n {#1} ,
    AlternateFont  .value_required:n = true ,
    CharRange .clist_set:N = \l_@@_char_range_clist ,
    CharRange .value_required:n = true
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_set_alternate_prop:n}
% 保存替代字体序列。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_set_alternate_prop:n #1
  { \clist_map_function:nN {#1} \@@_push_alternate_prop:n }
\cs_new_protected:Npn \@@_push_alternate_prop:n #1
  {
    \clist_set:Nx \l_@@_tmp_clist { \tl_head:n {#1} }
    \tl_remove_all:Nn \l_@@_tmp_clist { ~ }
    \exp_args:No \@@_push_alternate_prop:nn
      { \l_@@_tmp_clist } {#1}
  }
\cs_new_protected:Npn \@@_push_alternate_prop:nn #1
  {
    \prop_remove:Nn \l_@@_alternate_prop {#1}
    \prop_put:Nnn \l_@@_alternate_prop {#1}
  }
\clist_new:N \l_@@_tmp_clist
\prop_new:N \l_@@_alternate_prop
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_set_alternate_family:nnF}
% 如果在字体的选项中设置了 \opt{CharRange}，则只设置替代字体。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_set_alternate_family:nnF
  {
    \clist_if_empty:NTF \l_@@_char_range_clist
      { \@@_set_family_aux:nnn }
      { \@@_set_alternate_family_aux:nnn }
  }
\cs_new_protected:Npn \@@_set_family_aux:nnn #1#2#3
  {
    \@@_check_family:n {#1}
    \prop_if_empty:NF \l_@@_alternate_prop
      { \ctex_ltj_save_alternate_seq:cn { \@@_alternate_cs:n {#1} } {#2} }
    #3
  }
\cs_new_protected:Npn \@@_set_alternate_family_aux:nnn #1#2#3
  { \ctex_ltj_set_alternate_family:nn {#1} {#2} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_save_alternate_seq:Nn}
% 保存由 \opt{AlternateFont} 设置的替代字体序列。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_save_alternate_seq:Nn #1#2
  {
    \prop_map_inline:Nn \l_@@_alternate_prop
      { \@@_save_alternate_auxi:w ##2 { } \q_mark #1 {#2} }
  }
\cs_new_protected:Npn \@@_save_alternate_auxi:w #1#2#
  {
    \tl_if_blank:nTF {#2}
      { \@@_save_alternate_auxii:w {#1} }
      { \@@_save_alternate_auxii:w {#1} {#2} }
  }
\cs_new_protected:Npn \@@_save_alternate_auxii:w #1#2#3 #4 \q_mark #5#6
  {
    \clist_set:Nn \l_@@_char_range_clist {#1}
    \clist_set:Nn \l_@@_alternate_options_clist {#3}
    \@@_use_global_options:N \l_@@_alternate_options_clist
    \tl_if_blank:nTF {#2}
      { \tl_set:Nn \l_@@_tmp_tl {#6} }
      {
        \tl_set:Nx \l_@@_tmp_tl { \tl_trim_spaces:n {#2} }
        \tl_replace_all:Nnn \l_@@_tmp_tl { * } {#6}
      }
    \use:e
      {
        \ctex_ltj_save_alternate_family:Nnnn \exp_not:N #5
          { \exp_not:o { \l_@@_char_range_clist } }
          { \exp_not:o { \l_@@_alternate_options_clist } }
          { \exp_not:o { \l_@@_tmp_tl } }
      }
  }
\clist_new:N \l_@@_alternate_options_clist
\cs_generate_variant:Nn \ctex_ltj_save_alternate_seq:Nn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_set_alternate_family:nn}
% 设置选项 \opt{CharRange} 范围内的替代字体。如果已经定义了主字体，我们也马上
% 定义替代字体，否则只保存起来备用。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_set_alternate_family:nn #1#2
  {
    \@@_update_family_uid:N \l_@@_font_options_clist
    \@@_use_global_options:N \l_@@_font_options_clist
    \ctex_ltj_set_alternate_family:coonn
      { \@@_alternate_cs:n {#1} }
      { \l_@@_char_range_clist }
      { \l_@@_font_options_clist } {#2} {#1}
  }
\cs_new_protected:Npn \ctex_ltj_set_alternate_family:Nnnnn #1#2#3#4#5
  {
    \prop_get:NnNT \g_@@_family_name_prop {#5} \l_@@_base_family_tl
      { \ctex_ltj_set_alternate_family:nnn {#2} {#3} {#4} }
    \ctex_ltj_save_alternate_family:Nnnn #1 {#2} {#3} {#4}
  }
\cs_generate_variant:Nn \ctex_ltj_set_alternate_family:Nnnnn { coo }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_save_alternate_family:Nnnn}
% 保存替代字体序列的定义，以备定义主字体时使用。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_save_alternate_family:Nnnn #1#2#3#4
  {
    \cs_if_exist:NF #1 { \cs_set_eq:NN #1 \prg_do_nothing: }
    \cs_gset_protected:Npx #1
      { \exp_not:o { #1 \ctex_ltj_set_alternate_family:nnn {#2} {#3} {#4} } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_set_alternate_family:nnn}
% 实际定义替代字体族。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_set_alternate_family:nnn #1#2#3
  {
    \group_begin:
    \cs_set_eq:NN \CJKfamily \use_none:n
    \ctex_ltj_swap_cs:NN
      \DeclareFontShape@ \ctex_ltj_declare_alternate_shape:nnnnnn
    \tl_set:Nn \l_@@_char_range_clist {#1}
    \fontspec_set_family:Nnn \l_@@_alternate_family_tl {#2} {#3}
    \group_end:
  }
\tl_new:N \l_@@_alternate_family_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_swap_cs:NN}
% 交换两个控制序列的意义。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_swap_cs:NN #1#2
  {
    \cs_set_eq:NN \@@_tmp:w #1
    \cs_set_eq:NN #1 #2
    \cs_set_eq:NN #2 \@@_tmp:w
    \cs_undefine:N \@@_tmp:w
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{LTJFONTUID}
% \begin{macro}{\@@_update_family_uid:N}
% \pkg{fontspec} 在一个字体族的选项和字体名称相同的时候，就不定义新字体。为了
% 避免混淆替代字体的设置，我们新定义一个虚拟的选项 \opt{LTJFONTUID}，确保
% \pkg{fontspec} 对 CJK 字体族总是定义新字体。
%    \begin{macrocode}
\keys_define:nn { fontspec } { LTJFONTUID .code:n = }
\cs_new_protected:Npn \@@_update_family_uid:N #1
  {
    \int_gincr:N \g_@@_family_int
    \clist_put_right:Nx #1 { LTJFONTUID = \int_use:N \g_@@_family_int }
  }
\int_new:N \g_@@_family_int
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_declare_alternate_shape:nnnnnn}
% 在定义替代字体的字形时，通过字符范围与主字体的对应字形关联起来。
% \tn{DeclareFontShape@} 一个有六个参数，我们只需要使用它的第三个参数 \meta{series}
% 和第四个参数 \meta{shape}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_declare_alternate_shape:nnnnnn #1#2#3#4#5#6
  {
    \ctex_ltj_declare_alternate_shape:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}
    \ctex_ltj_set_alternate_shape:Nnnnnnn \l_@@_char_range_clist
      { \l_@@_base_family_tl } {#3} {#4} {#2} {#3} {#4}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_set_alternate_shape:Nnnnnnn}
% 与 \pkg{LuaTeX-ja} 的 \tn{DeclareAlternateKanjiFont} 的功能类似，区别是固定编码
% 为 \tn{CJK@encoding}。这个设置总是全局的。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_set_alternate_shape:Nnnnnnn #1#2#3#4#5#6#7
  {
    \clist_map_inline:Nn #1
      {
        \prop_get:NnNTF \g_@@_char_range_prop { ##1 } \l_@@_char_range_tl
          {
            \ctex_ltj_set_alternate_shape:nnN { #2/#3/#4 } { #5/#6/#7 }
              \l_@@_char_range_tl
          }
          { \ctex_ltj_set_alternate_shape:nnn { #2/#3/#4 } { #5/#6/#7 } { ##1 } }
      }
    \@@_save_alternate_shape:cn
      { \@@_alternate_cs:n { clear / \l_@@_base_CJKfamily_tl } }
      { \ctex_ltj_clear_alt_font:n { \CJK@encoding/#2/#3/#4 } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_set_alternate_shape:nnn}
% 我们使用 \texttt{-&gt;} 而不是像 \pkg{LuaTeX-ja} 一样使用 \texttt{-} 作为区间的
% 分隔符。\pkg{LuaTeX-ja} 支持使用负数来引用由 \texttt{JFM} 设置的字符类。如果
% 使用 \texttt{-} 作为分隔符，那么负数单独使用时，就需要把它放在两层花括号之内
% （例如 |{{-1}}|），或者使用类似 |{-1}-{-1}| 的形式才不会解释错误。
%    \begin{macrocode}
\NewDocumentCommand \ctex_ltj_set_alternate_shape:nnn
  { m m &gt; { \SplitArgument { 1 } { -&gt; } } m }
  { \ctex_ltj_set_alternate_shape:nnnn {#1} {#2} #3 }
\cs_new_protected:Npn \ctex_ltj_set_alternate_shape:nnnn #1#2#3#4
  {
    \ctex_ltj_set_alternate_shape:e
      {
        \@@_range_normalization:nn {#3} {#4}
        { \CJK@encoding / \exp_not:n {#2} }
        { \CJK@encoding / \exp_not:n {#1} }
      }
  }
\cs_new_protected:Npn \ctex_ltj_set_alternate_shape:n #1
  {
    \ctex_ltj_set_alt_font:nnnn #1
    \@@_save_alternate_shape:cn
      { \@@_alternate_cs:n { reset / \l_@@_base_CJKfamily_tl } }
      { \ctex_ltj_set_alt_font:nnnn #1 }
  }
\cs_generate_variant:Nn \ctex_ltj_set_alternate_shape:n { e }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_set_alternate_shape:nnN}
% 若字符范围预先由 \texttt{declarecharrange} 声明，则可以直接使用。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_set_alternate_shape:nnN #1#2#3
  {
    \tl_map_inline:Nn #3
      {
        \ctex_ltj_set_alternate_shape:n
          {
            ##1
            { \CJK@encoding/#2 }
            { \CJK@encoding/#1 }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_save_alternate_shape:Nn}
% 将实际设置的替换字形保存起来用于清除或恢复。
% 暂时令 \cs{l_@@_base_family_tl} 为 \cs{scan_stop:} 是让它不被展开，使得替换
% 字体的设置可以在 \tn{addCJKfontfeature} 中直接使用。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_save_alternate_shape:Nn #1#2
  {
    \group_begin:
      \cs_if_exist:NF #1 { \cs_set_eq:NN #1 \prg_do_nothing: }
      \cs_set_eq:NN \l_@@_base_family_tl \scan_stop:
      \cs_gset_protected:Npx #1 { \exp_not:o {#1} #2 }
    \group_end:
  }
\cs_generate_variant:Nn \@@_save_alternate_shape:Nn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{clearalternatefont,resetalternatefont}
% 清除和重置操作总是全局的。
%    \begin{macrocode}
\ctex_define:n
  {
    clearalternatefont    .code:n =
      { \clist_map_function:eN {#1} \ctex_ltj_clear_alternate_font:n } ,
    resetalternatefont    .code:n =
      { \clist_map_function:eN {#1} \ctex_ltj_reset_alternate_font:n } ,
    clearalternatefont .default:n = \l_ctex_ltj_family_tl ,
    resetalternatefont .default:n = \l_ctex_ltj_family_tl
  }
\cs_new_protected:Npn \ctex_ltj_clear_alternate_font:n #1
  {
    \group_begin:
      \ctex_ltj_family_if_exist:xNTF {#1} \l_@@_base_family_tl
        {
          \cs_if_exist_use:cT
            { \@@_alternate_cs:n { clear / #1 } }
            {
              \prop_gput:Nno \g_@@_reset_alternate_prop
                {#1} { \l_@@_base_family_tl }
              \tl_set_eq:NN \CJK@family \l_@@_base_family_tl
              \selectfont
            }
        }
        { \@@_family_unknown_warning:n {#1} }
    \group_end:
  }
\cs_new_protected:Npn \ctex_ltj_reset_alternate_font:n #1
  {
    \group_begin:
      \prop_gpop:NnNT \g_@@_reset_alternate_prop {#1} \CJK@family
        {
          \tl_set_eq:NN \l_@@_base_family_tl \CJK@family
          \use:c { \@@_alternate_cs:n { reset / #1 } }
          \selectfont
        }
    \group_end:
  }
\prop_new:N \g_@@_reset_alternate_prop
\cs_generate_variant:Nn \clist_map_function:nN { e }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{declarecharrange}
% 预先声明字符范围。
%    \begin{macrocode}
\ctex_define:n
  {
    declarecharrange .code:n = \ctex_ltj_declare_char_range:e {#1} ,
    declarecharrange .value_required:n = true
  }
\cs_new_protected:Npn \ctex_ltj_declare_char_range:n #1
  { \clist_map_inline:nn {#1} { \@@_declare_char_range:nn ##1 } }
\cs_generate_variant:Nn \ctex_ltj_declare_char_range:n { e }
\cs_new_protected:Npn \@@_declare_char_range:nn #1
  { \tl_trim_spaces_apply:nN {#1} \ctex_ltj_declare_char_range:nn }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_declare_char_range:nn}
% \begin{variable}{\g_@@_char_range_prop}
% |#1| 是名字，|#2| 是范围。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_declare_char_range:nn #1#2
  {
    \tl_clear:N \l_@@_char_range_tl
    \clist_map_function:nN {#2} \ctex_ltj_save_char_range:n
    \prop_gput:Nno \g_@@_char_range_prop {#1} { \l_@@_char_range_tl }
    \ctex_ltj_def_char_range_key:n {#1}
    \tl_clear:N \l_@@_char_range_tl
  }
\tl_new:N \l_@@_char_range_tl
\prop_new:N \g_@@_char_range_prop
%    \end{macrocode}
% \end{variable}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_save_char_range:n}
% 预先解释字符区间的意义。
%    \begin{macrocode}
\NewDocumentCommand \ctex_ltj_save_char_range:n
  { &gt; { \SplitArgument { 1 } { -&gt; } } m }
  { \ctex_ltj_save_char_range:nn #1 }
\cs_new_protected:Npn \ctex_ltj_save_char_range:nn #1#2
  {
    \tl_put_right:Nx \l_@@_char_range_tl
      { { \@@_range_normalization:nn {#1} {#2} } }
  }
\cs_new:Npn \@@_range_normalization:nn #1#2
  {
    \tl_if_novalue:nTF {#2}
      {
        { \int_eval:n {#1} }
        { \int_eval:n {#1} }
      }
      {
        { \int_eval:n { \tl_if_blank:nTF {#1} { \c_@@_range_min_int } {#1} } }
        { \int_eval:n { \tl_if_blank:nTF {#2} { \c_@@_range_max_int } {#2} } }
      }
  }
\int_const:Nn \c_@@_range_min_int { "80 }
\int_const:Nn \c_@@_range_max_int { \c_max_char_int }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_def_char_range_key:n}
% 在字体设置选项中定义字符范围键。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_def_char_range_key:n #1
  {
    \keys_if_exist:nnF { ctex_ltj / fontspec } {#1}
      {
        \keys_define:nn { ctex_ltj / fontspec }
          { #1 .code:n = \ctex_ltj_char_range_key:nn {#1} { ##1 } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_ltj_char_range_key:nn}
% 如果字符范围键没有值，则只设置的这个字符范围内的替代字体。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_char_range_key:nn #1#2
  {
    \tl_if_blank:nTF {#2}
      { \clist_set:Nn \l_@@_char_range_clist {#1} }
      { \@@_push_alternate_prop:nn {#1} { {#1} #2 } }
  }
%    \end{macrocode}
% \end{macro}
%
% \paragraph{其他设置}
%
% 在抄录环境中禁用 \opt{autospacing} 和 \opt{autoxspacing}。然而，\pkg{LuaTeX-ja}
% 还是会使 JAchar 自动折行。没有看到有简单的禁用折行的办法，可能需要设置所有的
% JAchar 的 \opt{prebreakpenalty} 或 \opt{postbreakpenalty} 为 \texttt{10000}：
% \begin{verbatim}
%   \directlua
%     {
%       luatexja.isglobal = tex.globaldefs &gt; 0 and "global" or ""
%       for i = 0x80, 0x10FFFF do
%         if luatexja.charrange.jcr_table_main[i] &gt; 0 and
%            luatexja.charrange.jcr_table_main[i] &lt; 218 and
%            luatexja.charrange.is_japanese_char_curlist(i) then
%           luatexja.stack.set_stack_table(luatexja.stack_table_index.PRE + i, 10000)
%         end
%       end
%     }
% \end{verbatim}
%    \begin{macrocode}
\AtBeginDocument
  {
    \ctex_appto_cmd:NnnTF \verbatim@font
      { \char_set_catcode_letter:n { 64 } }
      { \CTEX@verbatim@font@hook }
      { }
      { \ctex_patch_failure:N \verbatim@font }
  }
\cs_new_protected:Npn \CTEX@verbatim@font@hook
  { \ltjsetparameter { autospacing = false , autoxspacing = false } }
%    \end{macrocode}
%
% \begin{macro}{\@@@@italiccorr}
% \LaTeX{} 的倾斜校正也要重新定义。
%    \begin{macrocode}
\cs_set_eq:NN \@@@@italiccorr \/
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.4.12}{2018/01/27}{正确使用 \tn{ltjsetkanjiskip} 和 \tn{ltjsetxkanjiskip}。}
%
% \begin{macro}[int]{\ctex_ltj_set_kanjiskip:N,\ctex_ltj_set_xkanjiskip:N}
% \tn{ltjsetkanjiskip} 和 \tn{ltjsetxkanjiskip} 是相应的 \tn{ltjsetparameter}
% 的快捷方式，在使用他们时，要注意先使用 \tn{ltj@setpar@global}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_ltj_set_kanjiskip:N
  { \ltj@setpar@global \ltjsetkanjiskip }
\cs_new_protected:Npn \ctex_ltj_set_xkanjiskip:N
  { \ltj@setpar@global \ltjsetxkanjiskip }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%&lt;@@=ctex&gt;
%&lt;/luatex&gt;
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex-engine-uptex.def}}
%
%    \begin{macrocode}
%&lt;*uptex|aptex&gt;
%    \end{macrocode}
%
% \changes{v2.4}{2016/02/28}{初步支持 \upLaTeX。}
% \changes{v2.4.15}{2019/04/05}{显式补丁 \upLaTeX 的 \tn{rmfamily} 等字体命令。}
%
% 按 \pkg{CJK} 的命名习惯模拟 \tn{CJKfamily}。
%    \begin{macrocode}
\NewDocumentCommand \CJKfamily { m }
  { \kanjifamily {#1} \selectfont }
%    \end{macrocode}
%
% \changes{v2.4.15}{2019/04/05}{将 \upLaTeX 的默认字体由 \texttt{mc} 改为
%   \texttt{zhrm}，并启用 \tn{jfam}。}
%
% 将 \upLaTeX 的默认字体由 |mc| 改为 |zhrm|，并启用 \tn{jfam}。
%    \begin{macrocode}
\DeclareErrorKanjiFont    {JY2}{zhrm}{m}{n}{10}
\DeclareKanjiSubstitution {JY2}{zhrm}{m}{n}
\DeclareKanjiSubstitution {JT2}{zhrm}{m}{n}
\DeclareSymbolFont{mincho}{JY2}{zhrm}{m}{n}
\SetSymbolFont{mincho}{bold}{JY2}{zhrm}{bx}{n}
\jfam \symmincho
%    \end{macrocode}
%
% \begin{macro}[int]{\em}
% \changes{v2.4.2}{2016/05/15}{兼容 \upLaTeX{} 2016/05/07u00 的定义。}
% 取消 \upLaTeX{} 对 \tn{em} 使用 |\mcfamily|、|\gtfamily| 命令的重定义，恢复
% \LaTeXe{} 对 \tn{em} 的原始定义。如果用户已经重定义了 \tn{em}，则新定义保持
% 不变。\upLaTeX{} 2016/05/07u00 的定义有所变化，这一行为可以由用户通过 \pkg{platexrelease}
% 包改变，需要分支处理。
%    \begin{macrocode}
\ctex_patch_cmd_once:NnnnTF \em
  { \ExplSyntaxOff }
  { \eminnershape \else \gtfamily \itshape }
  { \eminnershape \else \itshape }
  { }
  {
    \ctex_patch_cmd:Nnn \em
      { \mcfamily \upshape \else \gtfamily \itshape }
      { \eminnershape \else \itshape }
  }
\cs_set_nopar:Npn \eminnershape { \upshape }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.4}{2016/04/24}{正确设置 \upTeX{} 下字体命令。}
% \begin{macro}[int]{\ctex_set_upfamily:nnn}
% 将 NFSS 字体族 |#1| 设置为 JFM 字体名 |#2|，粗体形式字体名 |#3|。其中字体名
% 形如 |upzhserif|，不包括表示方向的后缀 |-h| 与 |-v|。粗体字体名为空时不设置该
% 字形。本命令不设置字体映射，需要复用已有的字体映射或另行设置。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_set_upfamily:nnn #1#2#3
  {
    \DeclareKanjiFamily{JY2}{#1}{}
    \DeclareKanjiFamily{JT2}{#1}{}
    \DeclareFontShape{JY2}{#1}{m}{n}{&lt;-&gt;~ #2-h}{}
    \DeclareFontShape{JT2}{#1}{m}{n}{&lt;-&gt;~ #2-v}{}
    \tl_if_empty:nF {#3}
      {
        \DeclareFontShape{JY2}{#1}{b}{n}{&lt;-&gt;~ #3-h}{}
        \DeclareFontShape{JT2}{#1}{b}{n}{&lt;-&gt;~ #3-v}{}
        \DeclareFontShape{JY2}{#1}{bx}{n}{&lt;-&gt;~ #3-h}{}
        \DeclareFontShape{JT2}{#1}{bx}{n}{&lt;-&gt;~ #3-v}{}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_set_upmap:nnn}
% 设置 \upTeX{} 字体映射。|#1| 是形如 |upserif| 的 PS TFM 字体名，不带表示粗体
% 的后缀 |b| 与表示排版方向的后缀 |-h| 与 |-v|。|#2| 与 |#3| 是普通与粗体的实际
% 字体名。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_set_upmap:nnn #1#2#3
  {
    \ctex_set_zhmap:n
      {
        \special { pdf:mapline~#1-h~UniGB-UTF16-H~#2 }
        \special { pdf:mapline~#1-v~UniGB-UTF16-V~#2 }
        \tl_if_empty:nF {#3}
          {
            \special { pdf:mapline~#1b-h~UniGB-UTF16-H~#3 }
            \special { pdf:mapline~#1b-v~UniGB-UTF16-V~#3 }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_set_upmap_unicode:nnn}
% 设置 \upTeX{} 字体映射，使用 |unicode| CMap。参数同上。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_set_upmap_unicode:nnn #1#2#3
  {
    \ctex_set_zhmap:n
      {
        \special { pdf:mapline~#1-h~unicode~#2 }
        \special { pdf:mapline~#1-v~unicode~#2 }
        \tl_if_empty:nF {#3}
          {
            \special { pdf:mapline~#1b-h~unicode~#3 }
            \special { pdf:mapline~#1b-v~unicode~#3 }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_set_upfonts:nnnnnn}
% 设置 \upTeX{} 基本字体映射，按 \pkg{zhmetrics-uptex} 的定义，依次设置衬线体
% 正、粗、意大利，无衬线体正、粗，等宽体正——共 6 种字体，并分横排及直排。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_set_upfonts:nnnnnn #1#2#3#4#5#6
  {
    \ctex_set_upmap:nnn { upserif   } {#1} {#2}
    \ctex_set_upmap:nnn { upserifit } {#3} {}
    \ctex_set_upmap:nnn { upsans    } {#4} {#5}
    \ctex_set_upmap:nnn { upmono    } {#6} {}
  }
%    \end{macrocode}
% \end{macro}
%
% 以下命令只能在导言区使用。
%    \begin{macrocode}
\@onlypreamble \ctex_set_upfamily:nnn
\@onlypreamble \ctex_set_upmap:nnn
\@onlypreamble \ctex_set_upmap_unicode:nnn
\@onlypreamble \ctex_set_upfonts:nnnnnn
%    \end{macrocode}
%
% \changes{v2.4.7}{2016/12/27}{依赖 \pkg{pxeverysel} 宏包。}
%
% \pkg{everysel} 宏包（2011/10/28）未考虑 \upLaTeX{} 对 \tn{selectfont} 的修
% 改，需要引入 \pkg{pxeverysel} 宏包。
%    \begin{macrocode}
\bool_if:NT \c_@@_everysel_loaded_bool
  { \RequirePackage { pxeverysel } }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/uptex|aptex&gt;
%    \end{macrocode}
%
% \subsubsection{修改主要字体命令}
%
% \changes{v2.5.2}{2020/05/06}{兼容 \LaTeX\ 2020-02-02 之前的版本。}
% \changes{v2.5.4}{2020/06/07}{修正主要字体命令补丁。}
%
% 修改 \tn{rmfamily} 等主要字体命令，使得中文字体能随西文主要字体更新。
% \LaTeX\ 2020-02-02 以后的版本可以直接使用 \tn{@rmfamilyhook} 等钩子。
% 我们暂时需要处理旧内核的情况，以保持兼容性。
%
% \pkg{xeCJK} 和 \pkg{zhmCJK} 已经有相同的工作，本段代码不需要对他们使用。
%    \begin{macrocode}
%&lt;*pdftex|luatex|uptex|aptex&gt;
%&lt;pdftex&gt;\reverse_if:N \if_bool:N \g_@@_zhmCJK_bool
%    \end{macrocode}
%
% \changes{v2.5.5}{2020/10/17}{进一步应用 \LaTeX\ 2020/10/01 的新钩子。}
%
% \begin{macro}[int]{\ctex_provide_font_hook:NNN,\CTEX@rmfamilyhook}
% 给 \tn{rmfamily} 等字体命令加钩子，钩子名字统一为 \tn{CTEX@rmfamilyhook} 等。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_provide_font_hook:NNN #1#2
  {
    \exp_args:Nc \@@_provide_font_hook_aux:NNNN
      { CTEX \cs_to_str:N #2 } #1#2
  }
\cs_if_exist:NTF \ctex_gadd_ltxhook:nn
  {
    \cs_new_protected:Npn \@@_provide_font_hook_aux:NNNN #1#2#3#4
      {
        \tl_new:N #1
        \exp_args:Nx \ctex_gadd_ltxhook:nn { \cs_to_str:N #2 } {#1}
      }
  }
  {
    \cs_new_protected:Npn \@@_provide_font_hook_aux:NNNN #1#2#3#4
      {
        \tl_new:N #1
        \cs_if_exist:NTF #3
          { \tl_gput_right:Nn #3 {#1} }
%    \end{macrocode}
% 注意此处不能用 \cs{ctex_patch_cmd:Nnn} 来打补丁，因其会关闭 \LaTeXiii 语法，
% 但 \pkg{fontspec} 会在 \tn{rmfamily} 的命令中相应加入
% \cs{l__fontspec_rmfamily_encoding_tl} 等，导致补丁失败。
%    \begin{macrocode}
          { \ctex_parse_name:NN \tl_replace_once:Nnn #2 {#4} { #1#4 } }
      }
  }
\ctex_provide_font_hook:NNN \rmfamily \@rmfamilyhook \selectfont
\ctex_provide_font_hook:NNN \sffamily \@sffamilyhook \selectfont
\ctex_provide_font_hook:NNN \ttfamily \@ttfamilyhook \selectfont
%&lt;pdftex|luatex&gt;\ctex_provide_font_hook:NNN \normalfont \@defaultfamilyhook \usefont
%    \end{macrocode}
% \end{macro}
%
% 按 \pkg{CJK} 的命名习惯模拟部分命令，并设置默认字体。
%    \begin{macrocode}
\tl_if_exist:NF \CJKfamilydefault
  { \tl_const:Nn \CJKfamilydefault { \CJKrmdefault } }
%&lt;*pdftex|luatex&gt;
\tl_if_exist:NF \CJKrmdefault { \tl_const:Nn \CJKrmdefault { rm } }
\tl_if_exist:NF \CJKsfdefault { \tl_const:Nn \CJKsfdefault { sf } }
\tl_if_exist:NF \CJKttdefault { \tl_const:Nn \CJKttdefault { tt } }
\tl_gput_right:Nn \CTEX@rmfamilyhook { \CJKfamily { \CJKrmdefault } }
\tl_gput_right:Nn \CTEX@sffamilyhook { \CJKfamily { \CJKsfdefault } }
\tl_gput_right:Nn \CTEX@ttfamilyhook { \CJKfamily { \CJKttdefault } }
\tl_gput_right:Nn \CTEX@defaultfamilyhook { \CJKfamily { \CJKfamilydefault } }
%&lt;/pdftex|luatex&gt;
%    \end{macrocode}
% \upLaTeX 不需要补丁 \tn{normalfont}，只需要修改 \tn{kanjifamilydefault}。
%    \begin{macrocode}
%&lt;*uptex|aptex&gt;
\tl_if_exist:NF \CJKrmdefault { \tl_const:Nn \CJKrmdefault { zhrm } }
\tl_if_exist:NF \CJKsfdefault { \tl_const:Nn \CJKsfdefault { zhsf } }
\tl_if_exist:NF \CJKttdefault { \tl_const:Nn \CJKttdefault { zhtt } }
\tl_gput_right:Nn \CTEX@rmfamilyhook { \kanjifamily { \CJKrmdefault } }
\tl_gput_right:Nn \CTEX@sffamilyhook { \kanjifamily { \CJKsfdefault } }
\tl_gput_right:Nn \CTEX@ttfamilyhook { \kanjifamily { \CJKttdefault } }
\tl_gset:Nn \kanjifamilydefault { \CJKfamilydefault }
%&lt;/uptex|aptex&gt;
%    \end{macrocode}
%
% \pkg{zhmCJK} 判断结束。
%    \begin{macrocode}
%&lt;pdftex&gt;\fi:
%    \end{macrocode}
%
% 使修改立刻生效，保证导言区字体族正确。
%    \begin{macrocode}
\normalfont
%    \end{macrocode}
%
% 在导言区末尾更新 \tn{CJKfamilydefault}，\pdfTeX 已经在之前使用过此处代码。
%    \begin{macrocode}
%&lt;!pdftex&gt;\ctex_at_end_preamble:n { \ctex_update_default_family: }
%    \end{macrocode}
%
% \changes{v2.4}{2016/02/15}{正确更新 \pkg{CJK} 包的 \tn{CJKfamilydefault}。}
% \changes{v2.4.1}{2016/04/26}{正确更新 \upLaTeX{} 的 \tn{CJKfamilydefault}。}
%
% \begin{macro}[int]{\ctex_update_default_family:}
% 在导言区结束，如果 \tn{CJKfamilydefault} 没有被更改，则在此时根据西文字体的情况
% 更新 \tn{CJKfamilydefault}。\pkg{xeCJK} 已经有这个功能，不需要再调整。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_update_default_family:
  {
    \tl_if_eq:NNT \CJKfamilydefault \l_@@_family_default_init_tl
      {
        \group_begin:
          \cs_set_eq:NN \@@_family_default_wrap:n \exp_not:n
          \tl_gset:Nx \CJKfamilydefault
            {
              \str_case:onF { \familydefault }
                {
                  { \rmdefault } { \exp_not:N \CJKrmdefault }
                  { \sfdefault } { \exp_not:N \CJKsfdefault }
                  { \ttdefault } { \exp_not:N \CJKttdefault }
                }
                { \CJKfamilydefault }
            }
        \group_end:
      }
%    \end{macrocode}
% 使用 \LuaLaTeX{} 时，自动调整得到的 \tn{CJKfamilydefault} 可能没有定义，需要
% 确认它的存在性。使用 \pkg{CJK} 宏包或 \upLaTeX{}
% 时，\texttt{C19rm}、\texttt{JY2rm} 等总是有定义的，不需要确认。
%    \begin{macrocode}
%&lt;luatex&gt;    \ctex_ltj_ensure_default_family:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_family_default_init_tl}
% 往 \tn{CJKfamilydefault} 中加入标志，用于判断它是否被更改。
%    \begin{macrocode}
\tl_new:N \l_@@_family_default_init_tl
\cs_new_eq:NN \@@_family_default_wrap:n \use:n
\tl_set:Nx \l_@@_family_default_init_tl
  {
    \exp_not:N \@@_family_default_wrap:n
      { \exp_not:o { \CJKfamilydefault } }
  }
\tl_gset_eq:NN \CJKfamilydefault \l_@@_family_default_init_tl
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
%&lt;/pdftex|luatex|uptex|aptex&gt;
%    \end{macrocode}
%
% \changes{v2.0}{2014/04/16}{自动检测操作系统，载入对应的字体配置。}
% \changes{v2.5}{2019/10/25}{操作系统检测移动至载入中文字库处，且不再需要
%   依赖特定引擎。}
%
% \subsubsection{\pkg{hyperref} 兼容性处理}
%
% \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}
%&lt;*class|ctex&gt;
\@ifpackageloaded { hyperref }
  {
    \cs_new_protected:Npn \ctex_hypersetup:n #1
      { \hypersetup {#1} }
  }
  {
    \cs_new_protected:Npn \ctex_hypersetup:n #1
      { \PassOptionsToPackage {#1} { hyperref } }
  }
%&lt;/class|ctex&gt;
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.7}{2021/06/06}{禁用 \dvipdfmx\ 驱动的 \opt{unicode} 书签设置。}
%
% 在 \pdfTeX{} 下使用 \texttt{GBK} 编码，\dvipdfmx{} 驱动可以直接用它的
% \tn{special} 命令，其他模式用 \pkg{xCJK2uni} 宏包处理。使用 \texttt{UTF-8} 编
% 码时，\pkg{CJKutf8} 已经处理了书签问题，但仍需要设置 \opt{pdfencoding} 为
% \opt{unicode}，目的是在书签的开头写入 BOM (|\376\377|)，提示这是
% \texttt{UTF-16BE} 字节流。
% \pkg{hyperref} 2021-02-04 版开始默认设置 \opt{unicode} 为 \opt{true}，
% 对于 \dvipdfmx\ 驱动，我们需要禁用这个设置，为此设置 \opt{pdfencoding} 为 \opt{pdfdoc}。
%    \begin{macrocode}
%&lt;*pdftex&gt;
\ctex_hypersetup:n { driverfallback = dvipdfmx }
\str_if_eq:onTF { \g_@@_encoding_tl } { GBK }
  {
    \ctex_hypersetup:n { CJKbookmarks = true }
    \sys_if_output_pdf:TF
      { \ctex_at_end_package:nn { hyperref } { \RequirePackage { xCJK2uni } } }
      {
        \ctex_hypersetup:n { pdfencoding = pdfdoc }
        \ctex_at_end_package:nn { hyperref }
          {
            \str_if_eq:onTF { \Hy@driver } { hdvipdfm }
              {
                \ctex_at_shipout_first:n
                  { \special { pdf:tounicode~GBK-EUC-UCS2 } }
              }
              { \RequirePackage { xCJK2uni } }
          }
      }
  }
  { \ctex_hypersetup:n { pdfencoding = unicode } }
%&lt;/pdftex&gt;
%    \end{macrocode}
% \XeTeX 和 \LuaTeX 统一设置 \opt{pdfencoding} 为 \opt{unicode}。
%    \begin{macrocode}
%&lt;*xetex|luatex&gt;
\ctex_hypersetup:n { pdfencoding = unicode }
%&lt;/xetex|luatex&gt;
%    \end{macrocode}
%
% 我们假定 \upTeX{} 使用 \dvipdfmx{} 驱动输出，于是使用与 \pdfTeX{} 类似的设
% 置。注意 \upTeX{} 需要使用 UTF8-UTF16 的编码转换。
%    \begin{macrocode}
%&lt;*uptex|aptex&gt;
\ctex_hypersetup:n
  {
    driverfallback = dvipdfmx ,
    pdfencoding    = pdfdoc
  }
\ctex_at_end_package:nn { hyperref }
  {
    \ctex_at_shipout_first:n
      { \special { pdf:tounicode~UTF8-UTF16 } }
  }
%&lt;/uptex|aptex&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*pdftex|xetex|luatex|uptex|aptex&gt;
%    \end{macrocode}
%
% \subsubsection{\pkg{CJKfntef}、\pkg{xeCJKfntef} 相关设置}
%
% \changes{v2.0}{2015/03/25}{默认关闭 \pkg{CJKfntef} 或 \pkg{xeCJKfntef} 的彩
% 色设置。}
% \changes{v2.0}{2015/03/25}{\tn{CTEXunderdot}、\tn{CTEXunderline}、
% \tn{CTEXunderdblline}、\tn{CTEXunderwave}、\tn{CTEXsout}、\tn{CTEXxout} 是过
% 时命令；\env{CTEXfilltwosides} 是过时环境。}
% \changes{v2.5}{2019/11/10}{不再自动载入 \pkg{CJKfntef} 或 \pkg{xeCJKfntef} 宏包。}
% \changes{v2.5}{2019/11/10}{移除 \tn{CTEXunderdot}、\tn{CTEXunderline}、
% \tn{CTEXunderdblline}、\tn{CTEXunderwave}、\tn{CTEXsout}、\tn{CTEXxout}、
% \env{CTEXfilltwosides} 等命令和环境。}
%
% 对 \pdfTeX{} 与 \XeTeX{} 引擎，分别在 \pkg{CJKfntef}、\pkg{xeCJKfntef} 宏包
% 的末尾关闭彩色显式等多余格式。
%
%    \begin{macrocode}
%&lt;*pdftex&gt;
\ctex_at_end_package:nn { CJKfntef }
  {
    \normalem
    \cs_new_protected:Npn \@@_clear_fntef_color:n #1
      { \tl_clear:c { CJK#1color } }
%&lt;/pdftex&gt;
%&lt;*xetex&gt;
\ctex_at_end_package:nn { xeCJKfntef }
  {
    \@ifpackagelater { xeCJKfntef } { 2014/11/04 }
      {
        \cs_new_protected:Npn \@@_clear_fntef_color:n #1
          { \xeCJKsetup { #1 / format = { } } }
      }
      {
        \cs_new_protected:Npn \@@_clear_fntef_color:n #1
          { \tl_clear:c { CJK#1color } }
      }
%&lt;/xetex&gt;
%&lt;*pdftex|xetex&gt;
    \clist_map_inline:nn
      { underdot , underline , underdblline , underwave , sout , xout }
      { \@@_clear_fntef_color:n {#1} }
  }
%&lt;/pdftex|xetex&gt;
%    \end{macrocode}
%
% \subsubsection{\tn{ccwd} 的更新}
%
% \begin{macro}[int]{\ctex_update_ccwd:,\ccwd}
% \changes{v2.4.1}{2016/04/29}{正确设置 \upTeX{} 下的 \tn{ccwd}。}
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_update_ccwd:
%&lt;*pdftex|xetex&gt;
  {
    \hbox_set:Nn \l_@@_tmp_box { \CJKglue }
    \dim_set:Nn \ccwd { \box_wd:N \l_@@_tmp_box + \f@size \p@ }
  }
%&lt;/pdftex|xetex&gt;
%&lt;*luatex&gt;
  { \skip_set:Nn \ccwd { \ltjgetparameter { kanjiskip } + \zw } }
%&lt;/luatex&gt;
%&lt;*uptex|aptex&gt;
  { \skip_set:Nn \ccwd { 1zw + \tex_kanjiskip:D } }
%&lt;/uptex|aptex&gt;
\dim_new:N \ccwd
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_update_ccglue:}
% 更新字间距。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_update_ccglue:
%&lt;*pdftex|xetex&gt;
  {
    \cs_set_protected:Npn \CJKglue
      { \skip_horizontal:N \l_@@_ccglue_skip }
  }
%&lt;/pdftex|xetex&gt;
%&lt;*luatex&gt;
  { \ctex_ltj_set_kanjiskip:N \l_@@_ccglue_skip }
%&lt;/luatex&gt;
%&lt;*uptex|aptex&gt;
  { \skip_set_eq:NN \tex_kanjiskip:D \l_@@_ccglue_skip }
%&lt;/uptex|aptex&gt;
\skip_new:N \l_@@_ccglue_skip
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int,pTF]{\ctex_if_ccglue_touched:}
% 检查用户是否修改过汉字间距。
%    \begin{macrocode}
\prg_new_conditional:Npnn \ctex_if_ccglue_touched: { TF }
  {
%&lt;*pdftex|xetex&gt;
    \if_meaning:w \CJKglue \@@_ccglue:
      \prg_return_false: \else: \prg_return_true: \fi:
%&lt;/pdftex|xetex&gt;
%&lt;*luatex&gt;
    \skip_if_eq:nnTF { \l_@@_ccglue_skip } { \ltjgetparameter { kanjiskip } }
      { \prg_return_false: } { \prg_return_true: }
%&lt;/luatex&gt;
%&lt;*uptex|aptex&gt;
    \skip_if_eq:nnTF { \l_@@_ccglue_skip } { \tex_kanjiskip:D }
      { \prg_return_false: } { \prg_return_true: }
%&lt;/uptex|aptex&gt;
  }
%&lt;pdftex|xetex&gt;\ctex_at_end:n { \cs_new_eq:NN \@@_ccglue: \CJKglue }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_update_em_unit:}
% 将当前汉字的宽度保存到 \tn{ccwd} 中备用。不采用 \texttt{1em}，因为这时的
% \texttt{1em} 实际上来自西文字体的信息，未必等于汉字的宽度，这似乎在传统的
% \file{.tfm} 字体上表现更明显。在 \pdfTeX{} 和 \XeTeX{} 下，直接使用 |\f@size\p@|
% 作为汉字的宽度，这应该对大多数汉字字体都成立，但不适用于诸如“方正兰亭黑长”之类
% 的特殊字体。在 \XeTeX{} 可以用 \tn{fontcharwd} 来改进。而在 \pdfTeX{} 下，若使用
% \pkg{zhmetrics} 技术，所有的汉字共享同一个 \file{.tfm}，\tn{fontcharwd} 也就没有
% 意义。在 \LuaTeX{} 下，\pkg{LuaTeX-ja} 总是按照 JFM 中的设置输出汉字的宽度，可以
% 直接用 \tn{zw} 作为汉字宽度。\upTeX{} 可以直接使用原生的长度单位 |zw|。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_update_em_unit:
%&lt;pdftex|xetex&gt;  { \dim_set:Nn \ccwd { \f@size \p@ } }
%&lt;luatex&gt;  { \dim_set:Nn \ccwd { \zw } }
%&lt;uptex|aptex&gt;  { \dim_set:Nn \ccwd { 1zw } }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{其他}
%
% \begin{macro}[int]{\ctex_add_to_selectfont:n,\CTEX@selectfont@hook}
% \changes{v2.4.13}{2018/03/23}{修正导言区 \tn{selectfont} 钩子位置。}
% \changes{v2.5}{2020/04/19}{兼容 \pkg{KOMA-Script} 的 \tn{selectfont} 补丁。}
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_add_to_selectfont:n #1
  {
    \cs_set_protected:Npx \CTEX@selectfont@hook
      { \exp_not:o { \CTEX@selectfont@hook #1 } }
  }
\cs_new_eq:NN \CTEX@selectfont@hook \prg_do_nothing:
%    \end{macrocode}
% 使用 \pkg{everysel} 包的情况。
% \tn{EverySelectfont} 直到文档开始时才有效。为了 \tn{ccwd} 和 \pkg{LuaTeX-ja} 的
% 字体设置在导言区也可用，我们还需要在这里手工修改 \tn{selectfont}。\pkg{everysel}
% 宏包会用 \tn{CheckCommand} 来检查 \tn{selectfont} 是否为标准定义。我们修改了
% \tn{selectfont}，所以会给出一个警告。为了消除这个警告，在它检查之前，还原本来
% 定义。\pkg{pxeverysel} 宏包取消了检查，但也需要恢复定义，避免重复使用钩子。
% \pkg{KOMA-Script} 宏包也会进行检查，我们需要小心处理。
%    \begin{macrocode}
\bool_if:NTF \c_@@_everysel_loaded_bool
  {
    \cs_if_free:NF \@EverySelectfont@Init
      {
        \group_begin:
        \cs_set:Npn \@@_tmp:N #1
          {
            \tl_set:Nn \l_@@_tmp_tl {#1}
            \cs_new_eq:NN \CTEX@selectfont@save #1
            \cs_new_protected:Npn \@@_restore_selectfont:
              {
                \cs_if_free:NF \scr@new@selectfont
                  {
%    \end{macrocode}
% \pkg{CJK} 直接修改 \tn{selectfont} 和 \pkg{pxeverysel} 的补丁，
% 会使 \pkg{KOMA-Script} 的 \tn{par@update} 失效。
%    \begin{macrocode}
%&lt;*pdftex|uptex|aptex&gt;
                    \cs_if_free:NF \par@update
%&lt;*uptex|aptex&gt;
                      {
                        \tl_put_right:Nn \@EverySelectfont@Init
                          { \tl_put_right:Nn #1 { \par@update } }
                      }
%&lt;/uptex|aptex&gt;
%&lt;*pdftex&gt;
                      { \tl_put_right:Nn #1 { \par@update } }
                    \cs_set_eq:NN \scr@selectfont \CTEX@selectfont@save
%&lt;/pdftex&gt;
%&lt;/pdftex|uptex|aptex&gt;
                    \cs_set_eq:NN \scr@new@selectfont #1
%&lt;!pdftex&gt;                    \cs_set_eq:NN \CTEX@selectfont@save \scr@selectfont
                  }
                \tl_put_left:Nn \@EverySelectfont@Init
                  { \cs_set_eq:NN #1 \CTEX@selectfont@save }
                \cs_undefine:N \@@_restore_selectfont:
              }
          }
        \ctex_parse_name:NN \@@_tmp:N \selectfont
      \exp_last_unbraced:NNo \group_end:
      \ctex_patch_cmd_once:NnnnTF { \l_@@_tmp_tl }
        { \ExplSyntaxOff }
        { \size@update }
        { \CTEX@selectfont@hook \size@update }
        { \@@_restore_selectfont: }
        { \ctex_patch_failure:N \selectfont }
      }
    \cs_new_protected:Npn \ctex_gadd_selectfont_hook:n
      { \EverySelectfont }
  }
%    \end{macrocode}
% 使用 \LaTeX \ 2021-06-01 的新钩子，不使用 \pkg{everysel} 包的情况。
%    \begin{macrocode}
  {
    \cs_new_protected:Npn \ctex_gadd_selectfont_hook:n
      { \ctex_gadd_ltxhook:nn { selectfont } }
  }
%    \end{macrocode}
% \end{macro}
%
% \tn{CJK@plane} 有定义，说明处于 \pkg{CJK} 宏包的 \tn{CJKsymbol} 之内，不必使用钩子。
%    \begin{macrocode}
%&lt;*pdftex&gt;
\ctex_gadd_selectfont_hook:n
  { \cs_if_exist:NF \CJK@plane { \CTEX@selectfont@hook } }
%&lt;/pdftex&gt;
%&lt;*xetex|luatex|uptex|aptex&gt;
\ctex_gadd_selectfont_hook:n { \CTEX@selectfont@hook }
%&lt;/xetex|luatex|uptex|aptex&gt;
%    \end{macrocode}
%
% Attribute 寄存器 \tn{ltj@curjfnt} 的初始值是 $-1$，必须把它设置为一个有效的
% \texttt{font.id}，否则编译时会直接退出。
%    \begin{macrocode}
%&lt;*luatex&gt;
\ctex_add_to_selectfont:n
  {
    \ctex_ltj_select_font:
    \ctex_ltj_select_alternate_font:
  }
\tl_set:Nn \CJK@family { song } \selectfont
\tl_clear:N \CJK@family
%&lt;/luatex&gt;
%    \end{macrocode}
%
% \changes{v2.4.1}{2016/05/01}{随字体更新 \upTeX{} 的 \tn{xkanjiskip}。}
%
% \begin{macro}[int]{\ctex_update_xkanjiskip:}
% \begin{variable}{\l_@@_xkanjiskip_skip}
% \upTeX{} 和 \pkg{LuaTeX-ja} 对 \tn{xkanjiskip} 都是即时赋值。单位 \opt{zw} 与字体相关，因此
% 需要每次 \tn{selectfont} 的时候更新一次 \tn{xkanjiskip}。如果用户设置过
% \tn{xkanjiskip}，就不更新。注意，同 \TeX{} 的 \tn{baselineskip} 一样，如果在
% 一个段落内多次设置了 \tn{kanjiskip} 或 \tn{xkanjiskip}，只有最后的设置会影响
% 全段。
%    \begin{macrocode}
%&lt;*luatex|uptex|aptex&gt;
\cs_new_protected:Npn \ctex_update_xkanjiskip:
  {
    \skip_if_eq:nnT
%&lt;luatex&gt;      { \ltjgetparameter { xkanjiskip } } { \l_@@_xkanjiskip_skip }
%&lt;uptex|aptex&gt;      { \tex_xkanjiskip:D } { \l_@@_xkanjiskip_skip }
      {
        \skip_set:Nn \l_@@_xkanjiskip_skip { \l_@@_xkanjiskip_tl }
%&lt;luatex&gt;        \ctex_ltj_set_xkanjiskip:N \l_@@_xkanjiskip_skip
%&lt;uptex|aptex&gt;        \skip_set_eq:NN \tex_xkanjiskip:D \l_@@_xkanjiskip_skip
      }
  }
\tl_new:N \l_@@_xkanjiskip_tl
\tl_set:Nn \l_@@_xkanjiskip_tl
%&lt;luatex&gt;  { .25\zw plus 1pt minus 1pt }
%&lt;uptex|aptex&gt;  { .25zw plus 1pt minus 1pt }
\skip_new:N \l_@@_xkanjiskip_skip
\skip_set:Nn \l_@@_xkanjiskip_skip
%&lt;luatex&gt;  { \ltjgetparameter { xkanjiskip } }
%&lt;uptex|aptex&gt;  { \tex_xkanjiskip:D }
%    \end{macrocode}
% \end{variable}
% \end{macro}
%
%    \begin{macrocode}
\ctex_add_to_selectfont:n { \ctex_update_xkanjiskip: }
%&lt;/luatex|uptex|aptex&gt;
%    \end{macrocode}
%
% \changes{v2.4.10}{2017/07/23}{定义 \tn{cht}，\tn{cdp} 和 \tn{cwd}。}
%
% \begin{macro}[int]{\cht,\cdp,\cwd,\ctex_update_kanjisize:}
% 分别从 \file{.jfm} 中读取字符高度、深度和宽度，目前仅考虑横排的情况。
%    \begin{macrocode}
%&lt;*luatex&gt;
\dim_new:N \cht
\dim_new:N \cdp
\dim_new:N \cwd
\group_begin:
\char_set_catcode_space:n { 32 }
\lua_now:e
  {
    local nulltable = { }
    local fmt = luatexja.jfont.font_metric_table
    local getattribute = tex.getattribute
    local setdimen = tex.setdimen
    ctex.newluacmd("ctex_update_kanjisize:", function ()
      local ft = fmt[getattribute("ltj@curjfnt")] or nulltable
      local ft = ft and ft.char_type or nulltable
      local fk = ft and ft[0] or nulltable
      setdimen("cht", fk.height or 0)
      setdimen("cdp", fk.depth or 0)
      setdimen("cwd", fk.width or ft.zw or 0)
    end, "global", "protected")
  }
\group_end:
\ctex_add_to_selectfont:n { \ctex_update_kanjisize: }
%&lt;/luatex&gt;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{space}
% 在导言区或正文中设置忽略空格方式。
% \pdfTeX{} 和 \XeTeX{} 下初始设置为 \opt{auto}，\LuaTeX{}、\upTeX{} 下是无效
% 选项。
%    \begin{macrocode}
\ctex_define:n
  {
%&lt;*pdftex|xetex&gt;
    space .choice: ,
    space / true  .code:n =
%&lt;pdftex&gt;      { \ctex_ignorespaces_case:N \prg_do_nothing: } ,
%&lt;xetex&gt;      { \xeCJKsetup { CJKspace = true } } ,
    space / auto  .code:n =
%&lt;pdftex&gt;      { \ctex_ignorespaces_case:N \ctex_auto_ignorespaces: } ,
%&lt;xetex&gt;      { \xeCJKsetup { CJKspace = false } } ,
    space / false .code:n =
%&lt;pdftex&gt;      { \ctex_ignorespaces_case:N \tex_ignorespaces:D } ,
%&lt;xetex&gt;      { \xeCJKsetup { CJKspace = false } } ,
    space .default:n = { true } ,
    space .initial:n = { auto }
%&lt;/pdftex|xetex&gt;
%&lt;*luatex|uptex|aptex&gt;
    space .code:n =
      { \msg_warning:nn { ctex } { invalid-option } }
%&lt;/luatex|uptex|aptex&gt;
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{punct}
% 在导言区或正文中设置标点符号输出格式。\pkg{LuaTeX-ja} 设置的是字体的默认 \texttt{JFM}，
% 只会影响到之后设置的字体。\upTeX{} 暂时无效。
%    \begin{macrocode}
\ctex_define:n
  {
    punct .code:n =
      {
        \tl_set:Nx \l_@@_punct_tl {#1}
%&lt;pdftex&gt;        \punctstyle { \l_@@_punct_tl }
%&lt;xetex&gt;        \xeCJKsetup { PunctStyle = \l_@@_punct_tl }
%&lt;luatex&gt;        \ctex_set_jfm:o { \l_@@_punct_tl }
%&lt;uptex|aptex&gt;        \msg_warning:nn { ctex } { invalid-option }
      } ,
    punct .default:n = { quanjiao } ,
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%&lt;/pdftex|xetex|luatex|uptex|aptex&gt;
%    \end{macrocode}
%
% \subsubsection{载入引擎定义文件}
%
% 最后载入各个编译引擎的定义文件。
%    \begin{macrocode}
%&lt;class|ctex&gt;\ctex_file_input:n { \c_@@_engine_file_str }
%    \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}
%&lt;*class|ctex|ctexheading&gt;
\NewDocumentCommand \ctexset { } { \ctex_set:n }
%&lt;/class|ctex|ctexheading&gt;
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.0}{2015/03/21}{\tn{CTEXsetup}, \tn{CTEXoptions} 是过时命令。}
% \begin{macro}{\CTEXsetup,\CTEXoptions}
% 过时命令。
%    \begin{macrocode}
%&lt;*class|ctex&gt;
\NewDocumentCommand \CTEXsetup { +O { } &gt; { \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:Nx \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:
  {
    \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 &gt; \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:Nx \ctex_ziju:n {#1} \tex_ignorespaces:D }
\cs_new_protected:Npn \ctex_ziju:n #1
  {
    \tl_set:Nx \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 &gt; \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 &lt; 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:nnx { 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}{将标题汉化功能加入 \pkg{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 ,
%&lt;article&gt;    bibname        .tl_set:N = \refname
%&lt;book|report&gt;    bibname        .tl_set:N = \bibname
%&lt;*beamer&gt;
    algorithmname  .tl_set:N = \algorithmname ,
    bibname        .tl_set:N = \bibname ,
    refname        .tl_set:N = \refname ,
    continuation   .tl_set:N = \insertcontinuationtext
%&lt;/beamer&gt;
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*ctex&gt;
\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 }
          }
      }
  }
%&lt;/ctex&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/class|ctex&gt;
%    \end{macrocode}
%
% \subsection{中文化的标题结构}
%
% 本节内容在 \CTeX{} 文档类或打开 \opt{heading} 选项下生效。
%    \begin{macrocode}
%&lt;*class|heading&gt;
%    \end{macrocode}
%
% \subsubsection{定义标题格式选项}
%
% \begin{variable}{\c_@@_section_headings_seq}
% 保存 \tn{section} 级以下标题名字。
%    \begin{macrocode}
%&lt;*article|book|report&gt;
\seq_const_from_clist:Nn \c_@@_section_headings_seq
  { section , subsection , subsubsection , paragraph , subparagraph }
%&lt;/article|book|report&gt;
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\c_@@_headings_seq}
%    \begin{macrocode}
%&lt;*article|book|report&gt;
\seq_new:N \c_@@_headings_seq
\seq_gset_eq:NN \c_@@_headings_seq \c_@@_section_headings_seq
%&lt;book|report&gt;\seq_gput_left:Nn \c_@@_headings_seq { chapter }
\seq_gput_left:Nn \c_@@_headings_seq { part }
%&lt;/article|book|report&gt;
%&lt;*beamer&gt;
\seq_const_from_clist:Nn \c_@@_headings_seq
  { part , section , subsection }
%&lt;/beamer&gt;
%    \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:cx { CTEXthe#1 }
      {
        \exp_not:c { CTEX@pre#1 }
        \exp_not:c { CTEX@the#1 }
        \exp_not:c { CTEX@post#1 }
      }
    \tl_const:cx { 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 ,
%&lt;*article|book|report&gt;
        #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 } ,
%&lt;/article|book|report&gt;
        \@@_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 &gt; { \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:
%&lt;*book|report&gt;
\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 ,
  }
%&lt;/book|report&gt;
%&lt;*article|beamer&gt;
\tl_clear:N \l_@@_tmp_tl
%&lt;/article|beamer&gt;
%    \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.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}
%&lt;*article|book|report&gt;
%    \end{macrocode}
%
% \begin{macro}[int]{\CTEX@fixtopskip}
% 修正 \cls{book} 和 \cls{report} 类的 \tn{part} 和 \tn{chapter} 标题之前的多余空行。
%    \begin{macrocode}
%&lt;*book|report&gt;
\cs_new_protected:Npn \CTEX@fixtopskip
  {
    \CTEX@fixheadingskip
    \dim_compare:nNnF \tex_pagegoal:D &lt; \c_max_dim
      { \skip_sub:Nn \l_@@_heading_skip { \tex_topskip:D } }
  }
%&lt;/book|report&gt;
%    \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}
%&lt;*book|report&gt;
\cs_new_protected:Npn \CTEX@setthispagestyle #1
  { \exp_args:Ne \thispagestyle { \use:c { CTEX@#1@pagestyle } } }
%&lt;/book|report&gt;
%    \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}
%&lt;*book|report&gt;
\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 } }
      }
  }
%&lt;/book|report&gt;
%    \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}
%&lt;*article&gt;
\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}
%&lt;/article&gt;
%&lt;*book|report&gt;
\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}
%&lt;/book|report&gt;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@part}
%    \begin{macrocode}
%&lt;*article&gt;
\def\@part[#1]#2{%
  \ifnum \c@secnumdepth &gt;\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 &gt;\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}
%&lt;/article&gt;
%&lt;*book|report&gt;
\def\@part[#1]#2{%
  \ifnum \c@secnumdepth &gt;-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 &gt;-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}
%&lt;/book|report&gt;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@spart}
%    \begin{macrocode}
%&lt;*article&gt;
\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}
%&lt;/article&gt;
%&lt;*book|report&gt;
\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}
%&lt;/book|report&gt;
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@endpart}
%    \begin{macrocode}
%&lt;*book|report&gt;
\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}
%&lt;/book|report&gt;
%    \end{macrocode}
% \end{macro}
%
% \paragraph{chapter 的标题}
%
%    \begin{macrocode}
%&lt;*book|report&gt;
%    \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 &gt;\m@ne
%&lt;*book&gt;
    \if@mainmatter
%&lt;/book&gt;
      \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
%&lt;*book&gt;
    \else
      \CTEX@ifnamefalse
      \CTEX@makeanchor@chapter{\Hy@chapapp*}%
%     \addcontentsline{toc}{chapter}{#1}%
    \fi
%&lt;/book&gt;
  \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 &gt;\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}
%&lt;/book|report&gt;
%    \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 &lt;\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&gt;\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&gt;\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&gt;\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&gt;\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&gt;\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&gt;\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
  }
%&lt;*book|report&gt;
\cs_new:Npn \CTEX@chapter@tocline #1#2
  {
    \CTEXifname
      { \protect \numberline { \CTEXthechapter \hspace { .3em } } }
      { }
    #2
  }
%&lt;/book|report&gt;
%    \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
%&lt;*article&gt;
    \gdef \CTEX@presection { \CTEX@preappendix }
    \gdef \CTEX@thesection { \CTEX@appendix@number }
    \gdef \CTEX@postsection { \CTEX@postappendix }
    \gdef \CTEX@section@numbering { \CTEX@appendix@numbering }
%&lt;/article&gt;
%&lt;*book|report&gt;
    \gdef \CTEX@prechapter { \CTEX@preappendix }
    \gdef \CTEX@thechapter { \CTEX@appendix@number }
    \gdef \CTEX@postchapter { \CTEX@postappendix }
    \gdef \CTEX@chapter@numbering { \CTEX@appendix@numbering }
%&lt;/book|report&gt;
  }
%    \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
%&lt;article&gt;  { part , spart , sect , ssect }
%&lt;book|report&gt;  { 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:Nx #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:Nx #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 }
  {
%&lt;*book|report&gt;
    \tl_set:Nn \ttl@chapterout { \typeout { \CTEXthechapter } }
%&lt;/book|report&gt;
    \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}
%&lt;*article&gt;
\legacy_if:nTF { @twoside }
  {
    \ctex_patch_cmd:Nnn \ps@headings
      { \ifnum \c@secnumdepth &gt; \z@ \thesection \quad \fi }
      { \CTEXifname { \CTEXthesection \quad } { } }
    \ctex_patch_cmd:Nnn \ps@headings
      { \ifnum \c@secnumdepth &gt; \@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 &gt; \m@ne \thesection \quad \fi }
      { \CTEXifname { \CTEXthesection \quad } { } }
  }
%&lt;/article&gt;
%&lt;*book|report&gt;
\ctex_patch_cmd:Nnn \ps@headings
  {
%&lt;book&gt;    \ifnum \c@secnumdepth &gt; \m@ne \if@mainmatter
%&lt;report&gt;    \ifnum \c@secnumdepth &gt; \m@ne
      \@chapapp \ \thechapter . ~ \ %
%&lt;report&gt;    \fi
%&lt;book&gt;    \fi \fi
  }
  { \CTEXifname { \CTEXthechapter \quad } { } }
\legacy_if:nT { @twoside }
  {
    \ctex_patch_cmd:Nnn \ps@headings
      { \ifnum \c@secnumdepth &gt; \z@ \thesection . ~ \ \fi }
      { \CTEXifname { \CTEXthesection \quad } { } }
  }
%&lt;/book|report&gt;
%    \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 &gt; \z@ \thesection \hskip 1em \relax \fi }
      { \CTEXifname { \CTEXthesection \quad } { } }
    \ctex_patch_cmd:Nnn \f@nch@initialise
      { \ifnum \c@secnumdepth &gt; \@ne \thesubsection \hskip 1em \relax \fi }
      { \CTEXifname { \CTEXthesubsection \quad } { } }
    \ctex_patch_cmd:Nnn \f@nch@initialise
      { \ifnum \c@secnumdepth &gt; \m@ne \@chapapp\ \thechapter . ~ \ \fi }
      { \CTEXifname { \CTEXthechapter \quad } { } }
    \ctex_patch_cmd:Nnn \f@nch@initialise
      { \ifnum \c@secnumdepth &gt; \z@ \thesection . ~ \ \fi }
      { \CTEXifname { \CTEXthesection \quad } { } }
    \f@nch@initialise
%    \end{macrocode}
% \pkg{fancyhdr} 的 \opt{headings} 选项会重定义 \cs{ps@headings}，
% 这里也要打补丁。
%    \begin{macrocode}
    \@ifpackagewith { fancyhdr } { headings }
      {
%&lt;*article&gt;
        \legacy_if:nTF { @twoside }
          {
            \ctex_patch_cmd:Nnn \ps@headings
              { \ifnum \c@secnumdepth &gt; \z@ \thesection \quad \fi }
              { \CTEXifname { \CTEXthesection \quad } { } }
            \ctex_patch_cmd:Nnn \ps@headings
              { \ifnum \c@secnumdepth &gt; \@ne \thesubsection \quad \fi }
              { \CTEXifname { \CTEXthesubsection \quad } { } }
          }
          {
            \ctex_patch_cmd:Nnn \ps@headings
              { \ifnum \c@secnumdepth &gt; \z@ \thesection \quad \fi }
              { \CTEXifname { \CTEXthesection \quad } { } }
          }
%&lt;/article&gt;
%&lt;*book|report&gt;
        \ctex_patch_cmd:Nnn \ps@headings
          {
%&lt;book&gt;            \ifnum \c@secnumdepth &gt; \m@ne \if@mainmatter
%&lt;report&gt;            \ifnum \c@secnumdepth &gt; \m@ne
              \@chapapp \ \thechapter . ~ \ %
%&lt;report&gt;            \fi
%&lt;book&gt;            \fi \fi
          }
          { \CTEXifname { \CTEXthechapter \quad } { } }
        \legacy_if:nT { @twoside }
          {
            \ctex_patch_cmd:Nnn \ps@headings
              { \ifnum \c@secnumdepth &gt; \z@ \thesection . ~ \ \fi }
              { \CTEXifname { \CTEXthesection \quad } { } }
          }
%&lt;/book|report&gt;
      }
      { }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%&lt;/article|book|report&gt;
%    \end{macrocode}
%
% \subsubsection{\cls{beamer} 标题页模板的修改}
%
%    \begin{macrocode}
%&lt;*beamer&gt;
%    \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}
%&lt;/beamer&gt;
%    \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
  {
%&lt;*!beamer&gt;
    secnumdepth           .code:n = \ctex_heading_depth:ne { secnumdepth } {#1} ,
    secnumdepth .value_required:n = true ,
%&lt;/!beamer&gt;
    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
  {
%&lt;*article|beamer&gt;
    part          =  0 ,
%&lt;/article|beamer&gt;
%&lt;*book|report&gt;
    part          = -1 ,
    chapter       =  0 ,
%&lt;/book|report&gt;
    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&lt;#1&gt;| 为参数的宏
% |\p@&lt;#1&gt;|。\LaTeX{} 在定义计数器 |&lt;#1&gt;| 时，都会将 |\p@&lt;#1&gt;| 初始化为 \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:Nnx \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}{\ctex_cleveref_hook:,\@@_cleveref_hook_aux:N}
% 需要将\pkg{cleveref} 包对应命令中 |\p@|\meta{counter} 的参数及时展开，以兼容 \tn{labelformat}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_cleveref_hook:
  {
    \@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}
%&lt;/class|heading&gt;
%    \end{macrocode}
%
% \subsubsection{标题格式的 \opt{scheme} 定义}
%
% 下面使用 \CTeX 文档类的设置方式，\opt{plain} 模拟标准文档类直接定义或以
% \tn{@startsection} 设定的章节标题格式，\opt{chinese} 汉化的标题格式。
%
%    \begin{macrocode}
%&lt;*scheme&amp;(article|book|report|beamer)&gt;
%    \end{macrocode}
%
% \changes{v2.1}{2015/05/30}{修复 \cls{ctexbook} 和 \cls{ctexrep} 类的中文
% \opt{part/number} 选项初值为空的错误。}
% \changes{v2.2}{2015/06/30}{将中文版式下的 \texttt{part} 和 \texttt{chapter}
% 标题的 \opt{nameformat} 和 \opt{titleformat} 选项的初值合并到 \opt{format} 中。}
%
%    \begin{macrocode}
\ctex_set:nn { part }
  {
    aftertitle  = \par ,
%&lt;*article|book|report&gt;
    hang        = false ,
%&lt;/article|book|report&gt;
%&lt;*plain&gt;
    name        = \partname \space ,
%&lt;*article|book|report&gt;
    number      = \thepart ,
%&lt;/article|book|report&gt;
%&lt;*beamer&gt;
    number      = \insertromanpartnumber ,
%&lt;/beamer&gt;
%&lt;/plain&gt;
%&lt;*chinese&gt;
    number      = \chinese { part } ,
%&lt;/chinese&gt;
%&lt;*article&gt;
    beforeskip  = 4ex ,
    afterskip   = 3ex ,
%&lt;*plain&gt;
    format      = \raggedright ,
    nameformat  = \Large \bfseries ,
    aftername   = \par \nobreak ,
    titleformat = \huge \bfseries ,
    afterindent = false
%&lt;/plain&gt;
%&lt;*chinese&gt;
    format      = \Large \bfseries \centering ,
    aftername   = \quad ,
    afterindent = true
%&lt;/chinese&gt;
%&lt;/article&gt;
%&lt;*book|report&gt;
    aftername   = \par \vskip 20 \p@ ,
    beforeskip  = 0pt \@plus 1fil ,
    afterskip   = 0pt \@plus 1fil ,
    pagestyle   = plain ,
    break       = \if@openright \cleardoublepage \else \clearpage \fi ,
%&lt;*plain&gt;
    format      = \centering ,
    nameformat  = \huge \bfseries ,
    titleformat = \Huge \bfseries
%&lt;/plain&gt;
%&lt;*chinese&gt;
    format      = \huge \bfseries \centering
%&lt;/chinese&gt;
%&lt;/book|report&gt;
%&lt;*beamer&gt;
    format      = \centering ,
    nameformat  = \usebeamerfont { part ~ name }
                  \usebeamercolor [fg] { part ~ name } ,
    aftername   = \vskip 1em \par ,
    titleformat = \usebeamerfont { part ~ title }
%&lt;/beamer&gt;
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*book|report&gt;
\ctex_set:nn { chapter }
  {
    pagestyle   = plain ,
    aftertitle  = \par ,
    hang        = false ,
    beforeskip  = 50 \p@ ,
    afterskip   = 40 \p@ ,
    lofskip     = 10 \p@ ,
    lotskip     = 10 \p@ ,
    break       = \if@openright \cleardoublepage \else \clearpage \fi ,
%&lt;*plain&gt;
    name        = \chaptername \space ,
    number      = \thechapter ,
    format      = \raggedright ,
    nameformat  = \huge \bfseries ,
    aftername   = \par \nobreak \vskip 20 \p@ ,
    titleformat = \Huge \bfseries ,
    afterindent = false ,
    tocline     = \CTEXnumberline {#1} #2
%&lt;/plain&gt;
%&lt;*chinese&gt;
    number      = \chinese { chapter } ,
    format      = \huge \bfseries \centering ,
    aftername   = \quad ,
    afterindent = true
%&lt;/chinese&gt;
  }
%&lt;/book|report&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
\ctex_set:nn { section }
  {
%&lt;*article|book|report&gt;
    number      = \thesection ,
    aftername   = \quad ,
    aftertitle  = \@@@@par ,
    beforeskip  = 3.5ex \@plus 1ex \@minus .2ex ,
    afterskip   = 2.3ex \@plus .2ex ,
    runin       = false ,
    break       = \addpenalty \@secpenalty ,
%&lt;*plain&gt;
    format      = \Large \bfseries ,
    afterindent = false
%&lt;/plain&gt;
%&lt;*chinese&gt;
    format      = \Large \bfseries \centering ,
    afterindent = true
%&lt;/chinese&gt;
%&lt;/article|book|report&gt;
%&lt;*beamer&gt;
%&lt;*plain&gt;
    name        = \sectionname \space ,
%&lt;/plain&gt;
    format      = \centering ,
    number      = \insertsectionnumber ,
    nameformat  = \usebeamerfont { section ~ name }
                  \usebeamercolor [fg] { section ~ name } ,
    aftername   = \vskip 1em \par ,
    titleformat = \usebeamerfont { section ~ title } ,
    aftertitle  = \par
%&lt;/beamer&gt;
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\ctex_set:nn { subsection }
  {
%&lt;*article|book|report&gt;
    number      = \thesubsection ,
    format      = \large \bfseries ,
    aftername   = \quad ,
    aftertitle  = \@@@@par ,
    beforeskip  = 3.25ex \@plus 1ex \@minus .2ex ,
    afterskip   = 1.5ex  \@plus .2ex ,
    runin       = false ,
    break       = \addpenalty \@secpenalty ,
%&lt;*plain&gt;
    afterindent = false
%&lt;/plain&gt;
%&lt;*chinese&gt;
    afterindent = true
%&lt;/chinese&gt;
%&lt;/article|book|report&gt;
%&lt;*beamer&gt;
%&lt;*plain&gt;
    name        = \subsectionname \space ,
    number      = \insertsubsectionnumber ,
%&lt;/plain&gt;
%&lt;*chinese&gt;
    number      = \arabic { section } . \arabic { subsection } ,
%&lt;/chinese&gt;
    format      = \centering ,
    nameformat  = \usebeamerfont { subsection ~ name }
                  \usebeamercolor [fg] { subsection ~ name } ,
    aftername   = \vskip 1em \par ,
    titleformat = \usebeamerfont { subsection ~ title } ,
    aftertitle  = \par
%&lt;/beamer&gt;
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*article|book|report&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
\ctex_set:nn { subsubsection }
  {
    number      = \thesubsubsection ,
    format      = \normalsize \bfseries ,
    aftername   = \quad ,
    aftertitle  = \@@@@par ,
    beforeskip  = 3.25ex \@plus 1ex \@minus .2ex ,
    afterskip   = 1.5ex \@plus .2ex ,
    runin       = false ,
    break       = \addpenalty \@secpenalty ,
%&lt;*plain&gt;
    afterindent = false
%&lt;/plain&gt;
%&lt;*chinese&gt;
    afterindent = true
%&lt;/chinese&gt;
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\ctex_set:nn { paragraph }
  {
    number      = \theparagraph ,
    format      = \normalsize \bfseries ,
    aftername   = \quad ,
    beforeskip  = 3.25ex \@plus 1ex \@minus .2ex ,
    break       = \addpenalty \@secpenalty ,
%&lt;*plain&gt;
    afterindent = false
%&lt;/plain&gt;
%&lt;*chinese&gt;
    afterindent = true
%&lt;/chinese&gt;
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\ctex_set:nn { subparagraph }
  {
    number      = \thesubparagraph ,
    format      = \normalsize \bfseries ,
    aftername   = \quad ,
    beforeskip  = 3.25ex \@plus 1ex \@minus .2ex ,
    break       = \addpenalty \@secpenalty ,
%&lt;*plain&gt;
    afterindent = false
%&lt;/plain&gt;
%&lt;*chinese&gt;
    afterindent = true
%&lt;/chinese&gt;
  }
%    \end{macrocode}
%
% 处理 \opt{sub3section} 与 \opt{sub4section} 的格式。
%    \begin{macrocode}
\int_compare:nNnTF \g_@@_section_depth_int &gt; 2
  {
    \ctex_set:nn { paragraph }
      {
        aftertitle  = \@@@@par ,
        afterskip   = 1ex \@plus .2ex ,
        runin       = false
      }
  }
  {
    \ctex_set:nn { paragraph }
      {
        afterskip   = 1em ,
        runin       = true
      }
  }
\int_compare:nNnTF \g_@@_section_depth_int &gt; 3
  {
    \ctex_set:nn { subparagraph }
      {
        aftertitle  = \@@@@par ,
        afterskip   = 1ex \@plus .2ex ,
        runin       = false
      }
  }
  {
    \ctex_set:nn { subparagraph }
      {
        afterskip   = 1em ,
        runin       = true
      }
  }
\int_compare:nNnTF \g_@@_section_depth_int &gt; 2
  { \ctex_set:nn { subparagraph } { indent = \c_zero_dim } }
  { \ctex_set:nn { subparagraph } { indent = \parindent } }
%    \end{macrocode}
%
% 处理附录的格式。
%    \begin{macrocode}
\ctex_set:nn { appendix }
%&lt;*article&gt;
  { number      = \@Alph \c@section }
%&lt;/article&gt;
%&lt;*book|report&gt;
  {
    name        = \appendixname \space ,
    number      = \@Alph \c@chapter
  }
%&lt;/book|report&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/article|book|report&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/scheme&amp;(article|book|report|beamer)&gt;
%    \end{macrocode}
%
% \subsubsection{\pkg{ctex.sty} 的 \opt{heading} 选项}
%
%    \begin{macrocode}
%&lt;*ctex|ctexheading&gt;
%    \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.
  }
%&lt;ctex&gt;\bool_if:NTF \l_@@_heading_bool
%&lt;ctexheading&gt;\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:nnx { ctex } { not-standard-class } { \c_@@_class_tl }
      }
    \ctex_file_input:n { ctex-heading- \c_@@_class_tl .def }
  }
%&lt;ctex&gt;  { \ctex_scheme_input:o { \l_@@_scheme_tl } }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/ctex|ctexheading&gt;
%    \end{macrocode}
%
% \subsubsection{标题配置文件}
%
%    \begin{macrocode}
%&lt;*name&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
\keys_set_known:nn { ctex }
  {
    contentsname   = 目录 ,
    listfigurename = 插图 ,
    listtablename  = 表格 ,
    figurename     = 图 ,
    tablename      = 表 ,
    abstractname   = 摘要 ,
    indexname      = 索引 ,
    bibname        = 参考文献 ,
    appendixname   = 附录 ,
    proofname      = 证明 ,
    algorithmname  = 算法 ,
    refname        = 参考文献 ,
    continuation   = （续） ,
    part    / name = { 第 , 部分 } ,
    chapter / name = { 第 , 章 }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/name&gt;
%    \end{macrocode}
%
% \subsection{\opt{chinese} 方案的其他设置}
%
%    \begin{macrocode}
%&lt;*scheme&amp;chinese&gt;
%    \end{macrocode}
%
% \opt{chinese} 在标准文档类下的页面格式总采用 \texttt{headings}。
%    \begin{macrocode}
%&lt;article|book|report&gt;\pagestyle { headings }
%    \end{macrocode}
%
% 日期格式。
%    \begin{macrocode}
\ctex_set:n { today = small }
%    \end{macrocode}
%
% 若用户未设置宏包选项 \opt{autoindent}，则自动调整首行缩进。
%    \begin{macrocode}
\ctex_if_autoindent_touched:F
  { \ctex_set:n { autoindent = true } }
%    \end{macrocode}
%
% 使用标题定义时的设置。首先是命题名字汉化。\cls{beamer} 需要汉化定理名称。
%    \begin{macrocode}
%&lt;*!generic&gt;
\str_if_eq:onTF { \g_@@_encoding_tl } { GBK }
%&lt;*beamer&gt;
  {
    \uselanguage { ChineseGBK }
    \languagealias { chinese } { ChineseGBK }
    \ctex_file_input:n { ctex-name-gbk.cfg }
  }
  {
    \uselanguage { ChineseUTF8 }
    \languagealias { chinese } { ChineseUTF8 }
    \ctex_file_input:n { ctex-name-utf8.cfg }
  }
%    \end{macrocode}
% 让 \pkg{translator} 包优先查找中文翻译。
%    \begin{macrocode}
\clist_put_left:Nn \trans@languagepath { chinese }
%&lt;/beamer&gt;
%&lt;*!beamer&gt;
  { \ctex_file_input:n { ctex-name-gbk.cfg } }
  { \ctex_file_input:n { ctex-name-utf8.cfg } }
%    \end{macrocode}
%
% \changes{v2.4.1}{2016/05/09}{\cls{beamer} 不调整默认字体大小。}
% 对 \cls{beamer} 以外的文档类，若用户未设置宏包选项 \opt{zihao}，则设置 \tn{normalsize}
% 为五号字。\cls{beamer} 不调整默认字体大小。
%    \begin{macrocode}
\int_compare:nNnF \g_@@_font_size_int &gt; { -1 }
  { \int_gset:Nn \g_@@_font_size_int { 0 } }
%    \end{macrocode}
%
% \changes{v2.4.1}{2016/05/09}{\cls{beamer} 不调整默认行距。}
% 对 \cls{beamer} 以外的文档类，若用户未设置宏包选项 \opt{linespread}，则设置行
% 距初始值为 $1.3\times 1.2=1.56$ 倍字体大小。\cls{beamer} 不调整行距。
%    \begin{macrocode}
\fp_if_nan:nT { \l_@@_line_spread_fp }
  { \fp_set:Nn \l_@@_line_spread_fp { 1.3 } }
%&lt;/!beamer&gt;
%&lt;/!generic&gt;
%    \end{macrocode}
%
% 不使用标题定义时的通用设置，注意此处 \cs{c_@@_std_class_tl} 可能没有定义。
%    \begin{macrocode}
%&lt;*generic&gt;
\tl_if_eq:NnTF \c_@@_std_class_tl { beamer }
  {
    \str_if_eq:onTF { \g_@@_encoding_tl } { GBK }
      {
        \uselanguage { ChineseGBK }
        \languagealias { chinese } { ChineseGBK }
        \ctex_file_input:n { ctex-name-gbk.cfg }
      }
      {
        \uselanguage { ChineseUTF8 }
        \languagealias { chinese } { ChineseUTF8 }
        \ctex_file_input:n { ctex-name-utf8.cfg }
      }
    \clist_put_left:Nn \trans@languagepath { chinese }
  }
  {
    \str_if_eq:onTF { \g_@@_encoding_tl } { GBK }
      { \ctex_file_input:n { ctex-name-gbk.cfg } }
      { \ctex_file_input:n { ctex-name-utf8.cfg } }
    \int_compare:nNnF \g_@@_font_size_int &gt; { -1 }
      { \int_gset:Nn \g_@@_font_size_int { 0 } }
    \fp_if_nan:nT { \l_@@_line_spread_fp }
      { \fp_set:Nn \l_@@_line_spread_fp { 1.3 } }
%    \end{macrocode}
% \changes{v2.0.2}{2015/05/16}{修复加载 \pkg{ctex} 宏包后章节标题后第一段
% 无段首缩进的问题。}
% 若 \pkg{ctex} 宏包与标准文档类及其衍生文档类联用，则将载入 \pkg{indentfirst} 宏包，
% 实现章节标题后首个段落的段首缩进。
%    \begin{macrocode}
    \tl_if_exist:NT \c_@@_std_class_tl
      { \RequirePackage { indentfirst } }
  }
%&lt;/generic&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/scheme&amp;chinese&gt;
%    \end{macrocode}
%
% \subsection{中文字号}
%
%    \begin{macrocode}
%&lt;*class|ctex|ctexsize&gt;
%    \end{macrocode}
%
% \changes{v2.0}{2014/03/08}{将中文字号功能提取到可以独立使用的 \pkg{ctexsize}。}
%
% \begin{macro}{\zihao}
%    \begin{macrocode}
\NewDocumentCommand \zihao { m }
  { \exp_args:Nx \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}
% 基础行距是字号的 $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 \c_@@_font_size_prop
\seq_new:N \c_@@_font_size_seq
\cs_new_protected:Npn \@@_save_font_size:nn #1#2
  {
    \use:e
      {
        \prop_gput:Nnn \exp_not:N \c_@@_font_size_prop {#1}
          {
            { \dim_to_decimal:n {#2} }
            { \dim_to_decimal:n { (#2) * 6 / 5 } }
          }
      }
    \seq_gput_right:Nn \c_@@_font_size_seq {#1}
  }
\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 }
%    \end{macrocode}
% \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:Nx #1 { { \tl_head:N \l_@@_tmp_tl } } }
          { \tl_put_right:Nx #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}
%&lt;/class|ctex|ctexsize&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*c5size&gt;
\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 } { }
%&lt;/c5size&gt;
%&lt;*cs4size&gt;
\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 } { }
%&lt;/cs4size&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;ctexsize&gt;\normalsize
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*class|ctex&gt;
%    \end{macrocode}
%
% \subsection{更新行距}
%
% \cs{l_@@_line_spread_fp} 被设置了才有必要更新行距和 \tn{footnotesep}。
%    \begin{macrocode}
\fp_if_nan:nF { \l_@@_line_spread_fp }
  {
    \exp_args:Nx \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}
%
%    \begin{macrocode}
%&lt;/class|ctex&gt;
%    \end{macrocode}
%
% \subsubsection{列表环境的缩进}
%
% \begin{macro}[int]{\verse,\quotation}
% 只在使用文档类的时候修改诗歌和引用环境的缩进。
%    \begin{macrocode}
%&lt;*scheme&amp;chinese&amp;(article|book|report)&gt;
\ctex_patch_cmd:Nnn \verse { -1.5em } { -2 \ccwd }
\ctex_patch_cmd:Nnn \verse {  1.5em } {  2 \ccwd }
\ctex_patch_cmd:Nnn \quotation { 1.5em } { 2 \ccwd }
%&lt;/scheme&amp;chinese&amp;(article|book|report)&gt;
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%&lt;*class|ctex&gt;
%    \end{macrocode}
%
% \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:nnxx { 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:nnxx { 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:Nx \g_@@_fontset_tl {#1}
                    \ctex_load_fontset:
                  }
                  {
                    \msg_error:nnxx { 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{\pkg{ctex.cfg}}
%
%    \begin{macrocode}
\ctex_at_end:n { \ctex_file_input:n { ctex.cfg } }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/class|ctex&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*config&gt;
%%
%&lt;/config&gt;
%    \end{macrocode}
%
% \subsubsection{\pkg{ctexopts.cfg}}
%
% 这里仅为配置文件示例：使用 Windows 下的字体设置。
%    \begin{macrocode}
%&lt;*ctexopts&gt;
%%
%% \ctex_set:nn { option } { fontset = windows }
%&lt;/ctexopts&gt;
%    \end{macrocode}
%
% \subsection{字体定义文件}
%
% \subsubsection{传统定义方式}
%
% \changes{v2.4.15}{2019/04/05}{将 \texttt{JY2} 和 \texttt{JT2} 编码的字体定义提取到单独的文件中。}
%
%    \begin{macrocode}
%&lt;*c19|c70&gt;
%%
%% Chinese characters
%%
%&lt;c19&gt;%% character set: GBK (extension of GB 2312)
%&lt;c70&gt;%% character set: Unicode
%% font encoding: Unicode
%%
%&lt;/c19|c70&gt;
%    \end{macrocode}
%
% \pkg{CJK} 宏包使用的字体族。
%    \begin{macrocode}
%&lt;rm&amp;c19&gt;\DeclareFontFamily{C19}{rm}{\hyphenchar\font\m@ne}
%&lt;rm&amp;c70&gt;\DeclareFontFamily{C70}{rm}{\hyphenchar\font\m@ne}
%&lt;sf&amp;c19&gt;\DeclareFontFamily{C19}{sf}{\hyphenchar\font\m@ne}
%&lt;sf&amp;c70&gt;\DeclareFontFamily{C70}{sf}{\hyphenchar\font\m@ne}
%&lt;tt&amp;c19&gt;\DeclareFontFamily{C19}{tt}{\hyphenchar\font\m@ne}
%&lt;tt&amp;c70&gt;\DeclareFontFamily{C70}{tt}{\hyphenchar\font\m@ne}
%    \end{macrocode}
%
% \changes{v2.4}{2016/04/25}{提供 \upLaTeX{} 的 NFSS 字体定义。}
% \upLaTeX{} 使用的字体族。\upLaTeX 在 NFSS 下使用字体编码 |JY2| 和 |JT2| 来分别
% 表示横排与直排的日文。
%    \begin{macrocode}
%&lt;rm&amp;jy2&gt;\DeclareKanjiFamily{JY2}{zhrm}{}
%&lt;rm&amp;jt2&gt;\DeclareKanjiFamily{JT2}{zhrm}{}
%&lt;sf&amp;jy2&gt;\DeclareKanjiFamily{JY2}{zhsf}{}
%&lt;sf&amp;jt2&gt;\DeclareKanjiFamily{JT2}{zhsf}{}
%&lt;tt&amp;jy2&gt;\DeclareKanjiFamily{JY2}{zhtt}{}
%&lt;tt&amp;jt2&gt;\DeclareKanjiFamily{JT2}{zhtt}{}
%    \end{macrocode}
%
%
%    \begin{macrocode}
%&lt;*rm&gt;
%&lt;*c19&gt;
\DeclareFontShape{C19}{rm}{m}{n}{&lt;-&gt; CJK * gbksong}{\CJKnormal}
\DeclareFontShape{C19}{rm}{b}{n}{&lt;-&gt; CJK * gbkhei}{\CJKnormal}
\DeclareFontShape{C19}{rm}{bx}{n}{&lt;-&gt; CJK * gbkhei}{\CJKnormal}
\DeclareFontShape{C19}{rm}{m}{sl}{&lt;-&gt; CJK * gbksongsl}{\CJKnormal}
\DeclareFontShape{C19}{rm}{b}{sl}{&lt;-&gt; CJK * gbkheisl}{\CJKnormal}
\DeclareFontShape{C19}{rm}{bx}{sl}{&lt;-&gt; CJK * gbkheisl}{\CJKnormal}
\DeclareFontShape{C19}{rm}{m}{it}{&lt;-&gt; CJK * gbkkai}{\CJKnormal}
\DeclareFontShape{C19}{rm}{b}{it}{&lt;-&gt; CJKb * gbkkai}{\CJKbold}
\DeclareFontShape{C19}{rm}{bx}{it}{&lt;-&gt; CJKb * gbkkai}{\CJKbold}
%&lt;/c19&gt;
%&lt;*c70&gt;
\DeclareFontShape{C70}{rm}{m}{n}{&lt;-&gt; CJK * unisong}{\CJKnormal}
\DeclareFontShape{C70}{rm}{b}{n}{&lt;-&gt; CJK * unihei}{\CJKnormal}
\DeclareFontShape{C70}{rm}{bx}{n}{&lt;-&gt; CJK * unihei}{\CJKnormal}
\DeclareFontShape{C70}{rm}{m}{sl}{&lt;-&gt; CJK * unisongsl}{\CJKnormal}
\DeclareFontShape{C70}{rm}{b}{sl}{&lt;-&gt; CJK * uniheisl}{\CJKnormal}
\DeclareFontShape{C70}{rm}{bx}{sl}{&lt;-&gt; CJK * uniheisl}{\CJKnormal}
\DeclareFontShape{C70}{rm}{m}{it}{&lt;-&gt; CJK * unikai}{\CJKnormal}
\DeclareFontShape{C70}{rm}{b}{it}{&lt;-&gt; CJKb * unikai}{\CJKbold}
\DeclareFontShape{C70}{rm}{bx}{it}{&lt;-&gt; CJKb * unikai}{\CJKbold}
%&lt;/c70&gt;
%&lt;*jy2&gt;
\DeclareFontShape{JY2}{zhrm}{m}{n}{&lt;-&gt; upzhserif-h}{}
\DeclareFontShape{JY2}{zhrm}{m}{it}{&lt;-&gt; upzhserifit-h}{}
\DeclareFontShape{JY2}{zhrm}{b}{n}{&lt;-&gt; upzhserifb-h}{}
\DeclareFontShape{JY2}{zhrm}{bx}{n}{&lt;-&gt; upzhserifb-h}{}
%&lt;/jy2&gt;
%&lt;*jt2&gt;
\DeclareFontShape{JT2}{zhrm}{m}{n}{&lt;-&gt; upzhserif-v}{}
\DeclareFontShape{JT2}{zhrm}{m}{it}{&lt;-&gt; upzhserifit-v}{}
\DeclareFontShape{JT2}{zhrm}{b}{n}{&lt;-&gt; upzhserifb-v}{}
\DeclareFontShape{JT2}{zhrm}{bx}{n}{&lt;-&gt; upzhserifb-v}{}
%&lt;/jt2&gt;
%&lt;/rm&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*sf&gt;
%&lt;*c19&gt;
\DeclareFontShape{C19}{sf}{m}{n}{&lt;-&gt; CJK * gbkyou}{\CJKnormal}
\DeclareFontShape{C19}{sf}{b}{n}{&lt;-&gt; CJKb * gbkyou}{\CJKbold}
\DeclareFontShape{C19}{sf}{bx}{n}{&lt;-&gt; CJKb * gbkyou}{\CJKbold}
\DeclareFontShape{C19}{sf}{m}{sl}{&lt;-&gt; CJK * gbkyousl}{\CJKnormal}
\DeclareFontShape{C19}{sf}{b}{sl}{&lt;-&gt; CJKb * gbkyousl}{\CJKbold}
\DeclareFontShape{C19}{sf}{bx}{sl}{&lt;-&gt; CJKb * gbkyousl}{\CJKbold}
\DeclareFontShape{C19}{sf}{m}{it}{&lt;-&gt; CJK * gbkyou}{\CJKnormal}
\DeclareFontShape{C19}{sf}{b}{it}{&lt;-&gt; CJKb * gbkyou}{\CJKbold}
\DeclareFontShape{C19}{sf}{bx}{it}{&lt;-&gt; CJKb * gbkyou}{\CJKbold}
%&lt;/c19&gt;
%&lt;*c70&gt;
\DeclareFontShape{C70}{sf}{m}{n}{&lt;-&gt; CJK * uniyou}{\CJKnormal}
\DeclareFontShape{C70}{sf}{b}{n}{&lt;-&gt; CJKb * uniyou}{\CJKbold}
\DeclareFontShape{C70}{sf}{bx}{n}{&lt;-&gt; CJKb * uniyou}{\CJKbold}
\DeclareFontShape{C70}{sf}{m}{sl}{&lt;-&gt; CJK * uniyousl}{\CJKnormal}
\DeclareFontShape{C70}{sf}{b}{sl}{&lt;-&gt; CJKb * uniyousl}{\CJKbold}
\DeclareFontShape{C70}{sf}{bx}{sl}{&lt;-&gt; CJKb * uniyousl}{\CJKbold}
\DeclareFontShape{C70}{sf}{m}{it}{&lt;-&gt; CJK * uniyou}{\CJKnormal}
\DeclareFontShape{C70}{sf}{b}{it}{&lt;-&gt; CJKb * uniyou}{\CJKbold}
\DeclareFontShape{C70}{sf}{bx}{it}{&lt;-&gt; CJKb * uniyou}{\CJKbold}
%&lt;/c70&gt;
%&lt;*jy2&gt;
\DeclareFontShape{JY2}{zhsf}{m}{n}{&lt;-&gt; upzhsans-h}{}
\DeclareFontShape{JY2}{zhsf}{b}{n}{&lt;-&gt; upzhsansb-h}{}
\DeclareFontShape{JY2}{zhsf}{bx}{n}{&lt;-&gt; upzhsansb-h}{}
%&lt;/jy2&gt;
%&lt;*jt2&gt;
\DeclareFontShape{JT2}{zhsf}{m}{n}{&lt;-&gt; upzhsans-v}{}
\DeclareFontShape{JT2}{zhsf}{b}{n}{&lt;-&gt; upzhsansb-v}{}
\DeclareFontShape{JT2}{zhsf}{bx}{n}{&lt;-&gt; upzhsansb-v}{}
%&lt;/jt2&gt;
%&lt;/sf&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;*tt&gt;
%&lt;*c19&gt;
\DeclareFontShape{C19}{tt}{m}{n}{&lt;-&gt; CJK * gbkfs}{\CJKnormal}
\DeclareFontShape{C19}{tt}{b}{n}{&lt;-&gt; CJKb * gbkfs}{\CJKbold}
\DeclareFontShape{C19}{tt}{bx}{n}{&lt;-&gt; CJKb * gbkfs}{\CJKbold}
\DeclareFontShape{C19}{tt}{m}{sl}{&lt;-&gt; CJK * gbkfssl}{\CJKnormal}
\DeclareFontShape{C19}{tt}{b}{sl}{&lt;-&gt; CJKb * gbkfssl}{\CJKbold}
\DeclareFontShape{C19}{tt}{bx}{sl}{&lt;-&gt; CJKb * gbkfssl}{\CJKbold}
\DeclareFontShape{C19}{tt}{m}{it}{&lt;-&gt; CJK * gbkfs}{\CJKnormal}
\DeclareFontShape{C19}{tt}{b}{it}{&lt;-&gt; CJKb * gbkfs}{\CJKbold}
\DeclareFontShape{C19}{tt}{bx}{it}{&lt;-&gt; CJKb * gbkfs}{\CJKbold}
%&lt;/c19&gt;
%&lt;*c70&gt;
\DeclareFontShape{C70}{tt}{m}{n}{&lt;-&gt; CJK * unifs}{\CJKnormal}
\DeclareFontShape{C70}{tt}{b}{n}{&lt;-&gt; CJKb * unifs}{\CJKbold}
\DeclareFontShape{C70}{tt}{bx}{n}{&lt;-&gt; CJKb * unifs}{\CJKbold}
\DeclareFontShape{C70}{tt}{m}{sl}{&lt;-&gt; CJK * unifssl}{\CJKnormal}
\DeclareFontShape{C70}{tt}{b}{sl}{&lt;-&gt; CJKb * unifssl}{\CJKbold}
\DeclareFontShape{C70}{tt}{bx}{sl}{&lt;-&gt; CJKb * unifssl}{\CJKbold}
\DeclareFontShape{C70}{tt}{m}{it}{&lt;-&gt; CJK * unifs}{\CJKnormal}
\DeclareFontShape{C70}{tt}{b}{it}{&lt;-&gt; CJKb * unifs}{\CJKbold}
\DeclareFontShape{C70}{tt}{bx}{it}{&lt;-&gt; CJKb * unifs}{\CJKbold}
%&lt;/c70&gt;
%&lt;*jy2&gt;
\DeclareFontShape{JY2}{zhtt}{m}{n}{&lt;-&gt; upzhmono-h}{}
%&lt;/jy2&gt;
%&lt;*jt2&gt;
\DeclareFontShape{JT2}{zhtt}{m}{n}{&lt;-&gt; upzhmono-v}{}
%&lt;/jt2&gt;
%&lt;/tt&gt;
%    \end{macrocode}
%
% \subsubsection{预定义字库}
%
%    \begin{macrocode}
%&lt;*fontset&gt;
%    \end{macrocode}
%
% \paragraph{\opt{adobe}}
%
% \tn{pdfmapline} 不支持 OpenType 字体，因而 \opt{adobe} 字体集在 pdf 模式下
% 就没有定义。\opt{fandol} 的情况类似。
%    \begin{macrocode}
%&lt;*adobe&gt;
\ctex_fontset_case:nnnn
  { \ctex_fontset_error:n { adobe } }
  {
    \ctex_zhmap_case:nnn
      {
        \setCJKmainfont  { AdobeSongStd-Light.otf }
          [
            cmap       = UniGB-UTF16-H,
            BoldFont   = AdobeHeitiStd-Regular.otf,
            ItalicFont = AdobeKaitiStd-Regular.otf
          ]
        \setCJKsansfont { AdobeHeitiStd-Regular.otf }
          [ cmap = UniGB-UTF16-H ]
        \setCJKmonofont { AdobeFangsongStd-Regular.otf }
          [ cmap = UniGB-UTF16-H ]
        \setCJKfamilyfont { zhsong } { AdobeSongStd-Light.otf       }
          [ cmap = UniGB-UTF16-H ]
        \setCJKfamilyfont { zhhei  } { AdobeHeitiStd-Regular.otf    }
          [ cmap = UniGB-UTF16-H ]
        \setCJKfamilyfont { zhkai  } { AdobeKaitiStd-Regular.otf    }
          [ cmap = UniGB-UTF16-H ]
        \setCJKfamilyfont { zhfs   } { AdobeFangsongStd-Regular.otf }
          [ cmap = UniGB-UTF16-H ]
        \ctex_punct_set:n { adobe }
        \ctex_punct_map_family:nn   { \CJKrmdefault } { zhsong }
        \ctex_punct_map_family:nn   { \CJKsfdefault } { zhhei  }
        \ctex_punct_map_family:nn   { \CJKttdefault } { zhfs   }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei  }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault } { zhkai  }
      }
      {
        \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { adobe }
        \ctex_punct_set:n { adobe }
        \ctex_punct_map_family:nn   { \CJKrmdefault } { zhsong }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei  }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault } { zhkai  }
      }
      { \ctex_fontset_error:n { adobe } }
  }
  {
    \ctex_set_upfonts:nnnnnn
      { AdobeSongStd-Light.otf       }
      { AdobeHeitiStd-Regular.otf    }
      { AdobeKaitiStd-Regular.otf    }
      { AdobeHeitiStd-Regular.otf    }
      { AdobeHeitiStd-Regular.otf    }
      { AdobeFangsongStd-Regular.otf }
    \ctex_set_upfamily:nnn { zhsong } { upzhserif   } {}
    \ctex_set_upfamily:nnn { zhhei  } { upzhsans    } {}
    \ctex_set_upfamily:nnn { zhfs   } { upzhmono    } {}
    \ctex_set_upfamily:nnn { zhkai  } { upzhserifit } {}
  }
  {
    \setCJKmainfont { AdobeSongStd-Light       }
      [ BoldFont = AdobeHeitiStd-Regular, ItalicFont = AdobeKaitiStd-Regular ]
    \setCJKsansfont { AdobeHeitiStd-Regular    }
    \setCJKmonofont { AdobeFangsongStd-Regular }
    \setCJKfamilyfont { zhsong } { AdobeSongStd-Light       }
    \setCJKfamilyfont { zhhei  } { AdobeHeitiStd-Regular    }
    \setCJKfamilyfont { zhfs   } { AdobeFangsongStd-Regular }
    \setCJKfamilyfont { zhkai  } { AdobeKaitiStd-Regular    }
  }
%&lt;/adobe&gt;
%    \end{macrocode}
%
% \paragraph{\opt{fandol}}
%
%    \begin{macrocode}
%&lt;*fandol&gt;
\ctex_fontset_case:nnnn
  { \ctex_fontset_error:n { fandol } }
  {
    \ctex_zhmap_case:nnn
      {
        \setCJKmainfont { FandolSong-Regular.otf }
          [
            cmap       = UniGB-UTF16-H,
            BoldFont   = FandolSong-Bold.otf,
            ItalicFont = FandolKai-Regular.otf
          ]
        \setCJKsansfont { FandolHei-Regular.otf }
          [ cmap = UniGB-UTF16-H, BoldFont = FandolHei-Bold.otf ]
        \setCJKmonofont { FandolFang-Regular.otf }
          [ cmap = UniGB-UTF16-H ]
        \setCJKfamilyfont { zhsong } { FandolSong-Regular.otf }
          [ cmap = UniGB-UTF16-H, BoldFont = FandolSong-Bold.otf ]
        \setCJKfamilyfont { zhhei  } { FandolHei-Regular.otf  }
          [ cmap = UniGB-UTF16-H, BoldFont = FandolHei-Bold.otf  ]
        \setCJKfamilyfont { zhfs   } { FandolFang-Regular.otf }
          [ cmap = UniGB-UTF16-H ]
        \setCJKfamilyfont { zhkai  } { FandolKai-Regular.otf  }
          [ cmap = UniGB-UTF16-H ]
        \ctex_punct_set:n { fandol }
        \ctex_punct_map_family:nn   { \CJKrmdefault         } { zhsong  }
        \ctex_punct_map_family:nn   { \CJKsfdefault         } { zhhei   }
        \ctex_punct_map_family:nn   { \CJKttdefault         } { zhfs    }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault, zhsong } { zhsongb }
        \ctex_punct_map_bfseries:nn { \CJKsfdefault, zhhei  } { zhheib  }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault         } { zhkai   }
      }
      {
        \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { fandol }
        \ctex_punct_set:n { fandol }
        \ctex_punct_map_family:nn   { \CJKrmdefault } { zhsong }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei  }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault } { zhkai  }
      }
      { \ctex_fontset_error:n { fandol } }
  }
  {
    \ctex_set_upfonts:nnnnnn
      { FandolSong-Regular.otf }
      { FandolSong-Bold.otf    }
      { FandolKai-Regular.otf  }
      { FandolHei-Regular.otf  }
      { FandolHei-Bold.otf     }
      { FandolFang-Regular.otf }
    \ctex_set_upfamily:nnn { zhsong } { upzhserif   } { upzhserifb }
    \ctex_set_upfamily:nnn { zhhei  } { upzhsans    } { upzhsansb  }
    \ctex_set_upfamily:nnn { zhfs   } { upzhmono    } {}
    \ctex_set_upfamily:nnn { zhkai  } { upzhserifit } {}
  }
  {
    \setCJKmainfont { FandolSong-Regular }
      [
        Extension  = .otf,
        BoldFont   = FandolSong-Bold,
        ItalicFont = FandolKai-Regular
      ]
    \setCJKsansfont { FandolHei-Regular  }
      [ Extension = .otf, BoldFont = FandolHei-Bold ]
    \setCJKmonofont { FandolFang-Regular }
      [ Extension = .otf ]
    \setCJKfamilyfont { zhsong } { FandolSong-Regular }
      [ Extension = .otf, BoldFont = FandolSong-Bold ]
    \setCJKfamilyfont { zhhei  } { FandolHei-Regular  }
      [ Extension = .otf, BoldFont = FandolHei-Bold  ]
    \setCJKfamilyfont { zhfs   } { FandolFang-Regular }
      [ Extension = .otf ]
    \setCJKfamilyfont { zhkai  } { FandolKai-Regular  }
      [ Extension = .otf ]
  }
%&lt;/fandol&gt;
%    \end{macrocode}
%
% \paragraph{\opt{founder}}
%
% \changes{v2.4.15}{2019/03/28}{统一“方正细黑一\_GBK”的名称为 \texttt{FZXiHeiI-Z08}。}
%
%    \begin{macrocode}
%&lt;*founder&gt;
\ctex_fontset_case:nnn
  {
    \ctex_zhmap_case:nnn
      {
        \setCJKmainfont { FZSSK.TTF }
          [ BoldFont = FZXBSK.TTF, ItalicFont = FZKTK.TTF ]
        \setCJKsansfont { FZXH1K.TTF } [ BoldFont = FZHTK.TTF ]
        \setCJKmonofont { FZFSK.TTF }
        \setCJKfamilyfont { zhsong } { FZSSK.TTF } [ BoldFont = FZXBSK.TTF ]
        \setCJKfamilyfont { zhhei  } { FZHTK.TTF }
        \setCJKfamilyfont { zhkai  } { FZKTK.TTF }
        \setCJKfamilyfont { zhfs   } { FZFSK.TTF }
        \setCJKfamilyfont { zhli   } { FZLSK.TTF }
        \setCJKfamilyfont { zhyou  } { FZY1K.TTF } [ BoldFont = FZY3K.TTF ]
        \ctex_punct_set:n { founder }
        \ctex_punct_map_family:nn   { \CJKrmdefault         } { zhsong  }
        \ctex_punct_map_family:nn   { \CJKsfdefault         } { zhheil  }
        \ctex_punct_map_family:nn   { \CJKttdefault         } { zhfs    }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault         } { zhkai   }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault, zhsong } { zhsongb }
        \ctex_punct_map_bfseries:nn { \CJKsfdefault         } { zhhei   }
        \ctex_punct_map_bfseries:nn { zhyou                 } { zhyoub  }
      }
      {
        \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { founder }
        \ctex_punct_set:n { founder }
        \ctex_punct_map_family:nn   { \CJKrmdefault } { zhsong }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei  }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault } { zhkai  }
      }
      { \ctex_fontset_error:n { founder } }
  }
  {
    \ctex_set_upfonts:nnnnnn
      { FZSSK.TTF  }
      { FZXBSK.TTF }
      { FZKTK.TTF  }
      { FZXH1K.TTF }
      { FZHTK.TTF  }
      { FZFSK.TTF  }
    \ctex_set_upfamily:nnn { zhsong } { upzhserif   } { upzhserifb }
    \ctex_set_upfamily:nnn { zhhei  } { upzhsans    } { upzhsansb  }
    \ctex_set_upfamily:nnn { zhfs   } { upzhmono    } {}
    \ctex_set_upfamily:nnn { zhkai  } { upzhserifit } {}
    \ctex_set_upfamily:nnn { zhli   } { upschrm     } {}
    \ctex_set_upfamily:nnn { zhyou  } { upschgt     } {}
    \ctex_set_upmap:nnn    { upstsl } { FZLSK.TTF } {}
    \ctex_set_upmap:nnn    { upstht } { FZY1K.TTF } {}
  }
  {
    \setCJKmainfont { FZShuSong-Z01 }
      [ BoldFont = FZXiaoBiaoSong-B05, ItalicFont = FZKai-Z03 ]
    \setCJKsansfont { FZXiHeiI-Z08 } [ BoldFont = FZHei-B01 ]
    \setCJKmonofont { FZFangSong-Z02 }
    \setCJKfamilyfont { zhsong } { FZShuSong-Z01  }
      [ BoldFont = FZXiaoBiaoSong-B05 ]
    \setCJKfamilyfont { zhhei  } { FZHei-B01      }
    \setCJKfamilyfont { zhkai  } { FZKai-Z03      }
    \setCJKfamilyfont { zhfs   } { FZFangSong-Z02 }
    \setCJKfamilyfont { zhli   } { FZLiShu-S01    }
    \setCJKfamilyfont { zhyou  } { FZXiYuan-M01   }
      [ BoldFont = FZZhunYuan-M02 ]
  }
%&lt;/founder&gt;
%    \end{macrocode}
%
% \changes{v2.5.2}{2020/05/06}
%   {修正 \opt{macnew} 和 \opt{ubuntu} 字库的 \pkg{CJKpunct} 标点信息。}
%
% \paragraph{\opt{mac} 相关}
%
% \changes{v2.4.14}{2018/05/01}{区分 \opt{macold} 及 \opt{macnew}。}
%
% 按 \href{https://github.com/CTeX-org/ctex-kit/issues/351}{Issue 351}
% 的讨论，以 El Capitan 为分界，分别设置 |macold|（El Capitan 之前）
% 和 |macnew|（El Capitan 及之后）。检测方式则以 El Capitan 及之后
% 的苹方字体为准。
%
%    \begin{macrocode}
%&lt;*mac&gt;
\file_if_exist:nTF { /System/Library/Fonts/PingFang.ttc }
  { \ctex_file_input:n { ctex-fontset-macnew.def } }
  { \ctex_file_input:n { ctex-fontset-macold.def } }
%&lt;/mac&gt;
%    \end{macrocode}
%
% \changes{v2.4.14}{2018/05/01}{配置 \opt{macnew} 的默认字体设置。}
% \changes{v2.5}{2019/11/05}{为 \opt{macnew} 增加粗楷体、隶书和圆体的定义。}
% \changes{v2.5}{2019/11/07}{允许 \opt{macnew} 在 \LaTeX{} 和 \upLaTeX{} 下使用。}
%
% |macold| 的设置参考了
% \href{https://github.com/CTeX-org/ctex-kit/wiki/OS-X-Mavericks-(10.9)-预装的主要简体中文字体}^^A
% {OS X Mavericks (10.9) 预装的主要简体中文字体列表}。
%
% |macnew| 在默认字体设置方面，引入了多字重的宋体作为罗马字族，
% 以及引入了苹方黑体作为无衬线字族。
% 由于 Songti SC Light 的字重与 STSong 及 Windows 上的 SimSun 更接近，故默认字重
% 使用 Songti SC Light，而不带后缀的正常字重事实上没有使用。黑体、圆体等设置
% 也有类似的情况。
%
%    \begin{macrocode}
%&lt;*macold|macnew&gt;
\ctex_fontset_case:nnnn
  { \ctex_fontset_error:n { mac } }
%&lt;*macold&gt;
  { \ctex_fontset_error:n { macold } }
  { \ctex_fontset_error:n { macold } }
%&lt;/macold&gt;
%&lt;*macnew&gt;
  {
    \ctex_zhmap_case:nnn
      {
        \setCJKmainfont { :3:Songti.ttc }
          [
            BoldFont       = :1:Songti.ttc,
            ItalicFont     = :0:Kaiti.ttc,
            BoldItalicFont = :3:Kaiti.ttc,
          ]
        \setCJKsansfont { :2:PingFang.ttc } [ BoldFont = :8:PingFang.ttc ]
        \setCJKmonofont { STFANGSO.ttf    }
        \setCJKfamilyfont { zhsong } { :3:Songti.ttc   } [ BoldFont = :1:Songti.ttc   ]
        \setCJKfamilyfont { zhhei  } { :2:PingFang.ttc } [ BoldFont = :8:PingFang.ttc ]
        \setCJKfamilyfont { zhkai  } { :0:Kaiti.ttc    } [ BoldFont = :3:Kaiti.ttc    ]
        \setCJKfamilyfont { zhfs   } { STFANGSO.ttf    }
        \setCJKfamilyfont { zhli   } { :0:Baoli.ttc    }
        \setCJKfamilyfont { zhyou  } { :4:Yuanti.ttc   } [ BoldFont = :0:Yuanti.ttc   ]
        \ctex_punct_set:n { mac }
        \ctex_punct_map_family:nn   { \CJKrmdefault         } { zhsong  }
        \ctex_punct_map_family:nn   { \CJKsfdefault         } { zhpf    }
        \ctex_punct_map_family:nn   { \CJKttdefault         } { zhfs    }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault         } { zhkai   }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault, zhsong } { zhsongb }
        \ctex_punct_map_bfseries:nn { \CJKsfdefault, zhhei  } { zhpfb   }
        \ctex_punct_map_bfseries:nn { zhyou                 } { zhyoub  }
      }
      {
        \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { mac }
        \ctex_punct_set:n { mac }
        \ctex_punct_map_family:nn   { \CJKrmdefault } { zhsong }
        \ctex_punct_map_family:nn   { \CJKsfdefault } { zhpf   }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhpf   }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault } { zhkai  }
      }
      { \ctex_fontset_error:n { macnew } }
  }
  {
    \ctex_set_upmap:nnn { upserif   } { :3:Songti.ttc } { :1:Songti.ttc }
    \ctex_set_upmap:nnn { upserifit } { :0:Kaiti.ttc  } { }
    \ctex_set_upmap:nnn { upstsl    } { :0:Baoli.ttc  } { }
    \ctex_set_upmap:nnn { upstht    } { :4:Yuanti.ttc } { }
    \ctex_set_upmap_unicode:nnn { upsans } { :2:PingFang.ttc } { :8:PingFang.ttc }
    \ctex_set_upmap_unicode:nnn { upmono } { STFANGSO.ttf    } { }
    \ctex_set_upfamily:nnn { zhsong } { upzhserif   } { upzhserifb }
    \ctex_set_upfamily:nnn { zhhei  } { upzhsans    } { upzhsansb  }
    \ctex_set_upfamily:nnn { zhfs   } { upzhmono    } { }
    \ctex_set_upfamily:nnn { zhkai  } { upzhserifit } { }
    \ctex_set_upfamily:nnn { zhli   } { upschrm     } { }
    \ctex_set_upfamily:nnn { zhyou  } { upschgt     } { }
  }
%&lt;/macnew&gt;
  {
%&lt;*macold&gt;
    \setCJKmainfont { STSong     }
      [ BoldFont = STHeiti, ItalicFont = STKaiti ]
    \setCJKsansfont { STXihei    } [ BoldFont = STHeiti ]
    \setCJKmonofont { STFangsong }
    \setCJKfamilyfont { zhsong } { STSong     }
    \setCJKfamilyfont { zhhei  } { STHeiti    }
    \setCJKfamilyfont { zhfs   } { STFangsong }
    \setCJKfamilyfont { zhkai  } { STKaiti    }
%&lt;/macold&gt;
%&lt;*macnew&gt;
    \setCJKmainfont { Songti~SC~Light }
      [
        BoldFont       = Songti~SC~Bold,
        ItalicFont     = Kaiti~SC,
        BoldItalicFont = Kaiti~SC~Bold
      ]
    \setCJKsansfont { PingFang~SC }
    \setCJKmonofont { STFangsong  }
    \setCJKfamilyfont { zhsong } { Songti~SC~Light } [ BoldFont = Songti~SC~Bold ]
    \setCJKfamilyfont { zhhei  } { Heiti~SC~Light  } [ BoldFont = Heiti~SC~Medium ]
    \setCJKfamilyfont { zhpf   } { PingFang~SC     }
    \setCJKfamilyfont { zhfs   } { STFangsong      }
    \setCJKfamilyfont { zhkai  } { Kaiti~SC        } [ BoldFont = Kaiti~SC~Bold ]
    \setCJKfamilyfont { zhli   } { Baoli~SC        }
    \setCJKfamilyfont { zhyou  } { Yuanti~SC~Light } [ BoldFont = Yuanti~SC~Regular ]
%&lt;/macnew&gt;
  }
%&lt;/macold|macnew&gt;
%    \end{macrocode}
%
% \paragraph{\opt{ubuntu}}
%
% \changes{v2.5}{2019/11/07}{\opt{ubuntu} 改用思源（Noto CJK）和文鼎字库，不再
% 支持使用 \pdfLaTeX{} 编译。}
%
%    \begin{macrocode}
%&lt;*ubuntu&gt;
\ctex_fontset_case:nnnn
  { \ctex_fontset_error:n { ubuntu } }
  {
    \ctex_zhmap_case:nnn
      {
        \setCJKmainfont { :2:NotoSerifCJK-Regular.ttc }
          [ BoldFont = :2:NotoSerifCJK-Bold.ttc, ItalicFont = gkai00mp.ttf ]
        \setCJKsansfont { :2:NotoSansCJK-Regular.ttc  }
          [ BoldFont = :2:NotoSansCJK-Bold.ttc  ]
        \setCJKmonofont { :2:NotoSerifCJK-Regular.ttc }
          [ BoldFont = :2:NotoSerifCJK-Bold.ttc ]
        \setCJKfamilyfont { zhsong } { :2:NotoSerifCJK-Regular.ttc }
          [ BoldFont = :2:NotoSerifCJK-Bold.ttc ]
        \setCJKfamilyfont { zhhei  } { :2:NotoSansCJK-Regular.ttc  }
          [ BoldFont = :2:NotoSansCJK-Bold.ttc  ]
        \setCJKfamilyfont { zhkai  } { gkai00mp.ttf  }
        \ctex_punct_set:n { ubuntu }
        \ctex_punct_map_family:nn   { \CJKrmdefault        } { zhsong  }
        \ctex_punct_map_family:nn   { \CJKsfdefault        } { zhhei   }
        \ctex_punct_map_family:nn   { \CJKttdefault        } { zhsong  }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault        } { zhkai   }
        \ctex_punct_map_bfseries:nn { \CJKsfdefault, zhhei } { zhheib  }
        \ctex_punct_map_bfseries:nn
          { \CJKrmdefault, \CJKttdefault, zhsong }
          { zhsongb }
      }
      {
        \ctex_load_zhmap:nnnn { rm } { zhhei } { zhsong } { ubuntu }
        \ctex_punct_set:n { ubuntu }
        \ctex_punct_map_family:nn   { \CJKrmdefault } { zhsong }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei  }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault } { zhkai  }
      }
      { \ctex_fontset_error:n { ubuntu } }
  }
  {
    \ctex_set_upmap_unicode:nnn { upserif }
      { :2:NotoSerifCJK-Regular.ttc } { :2:NotoSerifCJK-Bold.ttc }
    \ctex_set_upmap_unicode:nnn { upsans  }
      { :2:NotoSansCJK-Regular.ttc  } { :2:NotoSansCJK-Bold.ttc  }
    \ctex_set_upmap_unicode:nnn { upmono  }
      { :2:NotoSerifCJK-Regular.ttc } { }
    \ctex_set_upmap:nnn { upserifit } { gkai00mp.ttf  } { }
    \ctex_set_upfamily:nnn { zhsong } { upzhserif   } { upzhserifb }
    \ctex_set_upfamily:nnn { zhhei  } { upzhsans    } { upzhsansb  }
    \ctex_set_upfamily:nnn { zhkai  } { upzhserifit } { }
  }
  {
    \setCJKmainfont { Noto~Serif~CJK~SC } [ ItalicFont = AR~PL~KaitiM~GB ]
    \setCJKsansfont { Noto~Sans~CJK~SC  }
    \setCJKmonofont { Noto~Serif~CJK~SC }
    \setCJKfamilyfont { zhsong } { Noto~Serif~CJK~SC }
    \setCJKfamilyfont { zhhei  } { Noto~Sans~CJK~SC  }
    \setCJKfamilyfont { zhkai  } { AR~PL~KaitiM~GB   }
  }
%&lt;/ubuntu&gt;
%    \end{macrocode}
%
% \paragraph{\opt{windows}}
%
% \changes{v2.4.1}{2016/05/14}{使用 \file{bootfont.bin} 判断 Windows XP 以避免
%   权限问题。}
% \changes{v2.5}{2019/11/04}{使用环境变量代替绝对路径查找字体。}
% \changes{v2.5}{2019/11/05}{不再支持 Windows XP 系统，\opt{windowsold} 和
%   \opt{windowsnew} 成为过时字库选项。}
%
% \begin{variable}{ \c_@@_msyh_suffix_tl}
% Windows 8 以后，微软雅黑由原来的 \file{.ttf} 后缀改为 \file{.ttc} 后缀，需要
% 加以区分。
%    \begin{macrocode}
%&lt;*windows&gt;
\file_if_exist:nTF { \c_dollar_str WINDIR/Fonts/msyh.ttc }
  { \tl_const:Nn \c_@@_msyh_suffix_tl { ttc } }
  {
    \file_if_exist:nTF { msyh.ttc }
      { \tl_const:Nn \c_@@_msyh_suffix_tl { ttc } }
      { \tl_const:Nn \c_@@_msyh_suffix_tl { ttf } }
  }
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
\ctex_fontset_case:nnn
  {
    \ctex_zhmap_case:nnn
      {
        \ctex_punct_set:n { windows }
        \setCJKmainfont { simsun.ttc }
          [ BoldFont = simhei.ttf, ItalicFont = simkai.ttf ]
        \setCJKsansfont { msyh.\c_@@_msyh_suffix_tl }
          [ BoldFont = msyhbd.\c_@@_msyh_suffix_tl ]
        \setCJKmonofont { simfang.ttf }
        \setCJKfamilyfont { zhsong  } { simsun.ttc  }
        \setCJKfamilyfont { zhhei   } { simhei.ttf  }
        \setCJKfamilyfont { zhfs    } { simfang.ttf }
        \setCJKfamilyfont { zhkai   } { simkai.ttf  }
        \setCJKfamilyfont { zhyahei } { msyh.\c_@@_msyh_suffix_tl }
          [ BoldFont = msyhbd.\c_@@_msyh_suffix_tl ]
        \setCJKfamilyfont { zhli    } { simli.ttf   }
        \setCJKfamilyfont { zhyou   } { simyou.ttf  }
        \ctex_punct_map_family:nn   { \CJKrmdefault          } { zhsong   }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault          } { zhhei    }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault          } { zhkai    }
        \ctex_punct_map_family:nn   { \CJKsfdefault          } { zhyahei  }
        \ctex_punct_map_bfseries:nn { \CJKsfdefault, zhyahei } { zhyaheib }
        \ctex_punct_map_family:nn   { \CJKttdefault          } { zhfs     }
      }
      {
        \ctex_load_zhmap:nnnn { rm } { zhhei } { zhfs } { windows }
        \ctex_punct_set:n { windows }
        \ctex_punct_map_family:nn   { \CJKrmdefault } { zhsong }
        \ctex_punct_map_bfseries:nn { \CJKrmdefault } { zhhei  }
        \ctex_punct_map_itshape:nn  { \CJKrmdefault } { zhkai  }
      }
      { }
  }
  {
    \ctex_set_upfonts:nnnnnn
      { simsun.ttc                   }
      { simhei.ttf                   }
      { simkai.ttf                   }
      { msyh.\c_@@_msyh_suffix_tl    }
      { msyhbd.\c_@@_msyh_suffix_tl  }
      { simfang.ttf                  }
    \ctex_set_upfamily:nnn { zhsong  } { upzhserif   } {}
    \ctex_set_upfamily:nnn { zhhei   } { upzhserifb  } {}
    \ctex_set_upfamily:nnn { zhfs    } { upzhmono    } {}
    \ctex_set_upfamily:nnn { zhkai   } { upzhserifit } {}
    \ctex_set_upfamily:nnn { zhyahei } { upzhsans    } { upzhsansb }
    \ctex_set_upfamily:nnn { zhli    } { upschrm     } {}
    \ctex_set_upfamily:nnn { zhyou   } { upschgt     } {}
    \ctex_set_upmap:nnn { upstsl } { simli.ttf  } {}
    \ctex_set_upmap:nnn { upstht } { simyou.ttf } {}
  }
  {
    \setCJKmainfont   { SimSun } [ BoldFont = SimHei , ItalicFont = KaiTi ]
    \setCJKsansfont   { Microsoft~YaHei } [ BoldFont = *~Bold ]
    \setCJKmonofont   { FangSong }
    \setCJKfamilyfont { zhsong  } { SimSun          }
    \setCJKfamilyfont { zhhei   } { SimHei          }
    \setCJKfamilyfont { zhfs    } { FangSong        }
    \setCJKfamilyfont { zhkai   } { KaiTi           }
    \setCJKfamilyfont { zhyahei } { Microsoft~YaHei } [ BoldFont = *~Bold ]
    \setCJKfamilyfont { zhli    } { LiSu            }
    \setCJKfamilyfont { zhyou   } { YouYuan         }
  }
%&lt;/windows&gt;
%    \end{macrocode}
%
% \subsubsection{中文字体命令}
% \changes{v2.4.14}{2018/05/01}{为 \opt{macnew} 配置字体命令。}
%
% \begin{macro}{\songti,\heiti,\fangsong,\kaishu,\lishu,\youyuan,\yahei,\pingfang}
% 使用 \upLaTeX{} 编译时，\opt{macnew} 字库中由于传统黑体（黑体-简）无法使用，
% 我们用苹方来代替。同时 \tn{yahei}、\tn{pingfang} 命令被设置为与 \tn{heiti} 相同。
%    \begin{macrocode}
%&lt;*!mac&gt;
\NewDocumentCommand \songti   { } { \CJKfamily { zhsong  } }
\NewDocumentCommand \heiti    { } { \CJKfamily { zhhei   } }
%&lt;!ubuntu&gt;\NewDocumentCommand \fangsong { } { \CJKfamily { zhfs    } }
\NewDocumentCommand \kaishu   { } { \CJKfamily { zhkai   } }
%&lt;*windows|founder|macnew&gt;
\NewDocumentCommand \lishu    { } { \CJKfamily { zhli    } }
\NewDocumentCommand \youyuan  { } { \CJKfamily { zhyou   } }
%&lt;/windows|founder|macnew&gt;
%&lt;windows&gt;\NewDocumentCommand \yahei    { } { \CJKfamily { zhyahei } }
%&lt;*macnew&gt;
\bool_lazy_or:nnTF
  { \sys_if_engine_pdftex_p: }
  { \sys_if_engine_uptex_p:  }
  {
    \cs_new_eq:NN \yahei    \heiti
    \cs_new_eq:NN \pingfang \heiti
  }
  {
    \NewDocumentCommand \yahei    { } { \CJKfamily { zhpf } }
    \NewDocumentCommand \pingfang { } { \CJKfamily { zhpf } }
  }
%&lt;/macnew&gt;
%&lt;/!mac&gt;
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%&lt;/fontset&gt;
%    \end{macrocode}
%
% \subsubsection{\pkg{zhmetrics} 的字体映射}
%
% \changes{v2.5.2}{2020/05/05}{\file{zhadobefonts.tex} 等字体映射文件更名为
%   \file{ctex-zhmap-*.tex}。}
%
% 确认 \tn{catcode}，没有重复载入检查。
%    \begin{macrocode}
%&lt;*zhmap&gt;
\begingroup\catcode61\catcode48\catcode32=10\relax%
  \catcode 35=6  % #
  \catcode 45=12 % -
  \catcode123=1  % {
  \catcode125=2  % }
  \toks0{\endlinechar=\the\endlinechar\relax}%
  \toks2{\endlinechar=-1 }%
  \def\x#1 #2 {%
    \toks0\expandafter{\the\toks0 \catcode#1=\the\catcode#1\relax}%
    \toks2\expandafter{\the\toks2 \catcode#1=#2 }}%
  \x  13  5 % carriage return
  \x  32 10 % space
  \x  35  6 % #
  \x  40 12 % (
  \x  41 12 % )
  \x  45 12 % -
  \x  46 12 % .
  \x  47 12 % /
  \x  58 12 % :
  \x  60 12 % &lt;
  \x  61 12 % =
  \x  64 11 % @
  \x  91 12 % [
  \x  93 12 % ]
  \x 123  1 % {
  \x 125  2 % }
  \edef\x#1{\endgroup%
    \edef\noexpand#1{%
      \the\toks0 %
      \let\noexpand\noexpand\noexpand#1%
          \noexpand\noexpand\noexpand\undefined%
      \noexpand\noexpand\noexpand\endinput}%
    \the\toks2}%
\expandafter\x\csname ctex@zhmap@endinput\endcsname
%    \end{macrocode}
%
% \begin{macro}[int]{\ifzhmappdf}
%    \begin{macrocode}
\begingroup\expandafter\endgroup
\expandafter\let\csname ifzhmappdf\expandafter\endcsname\csname
  \expandafter\ifx\csname ifctexpdf\endcsname\relax
    \expandafter\ifx\csname pdfoutput\endcsname\relax
      iffalse\else\ifnum\pdfoutput &lt; 1 iffalse\else iftrue\fi\fi
  \else ifctexpdf\fi
\endcsname
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ProvidesFile}
% 提供非 \LaTeX{} 格式下的 \tn{ProvidesFile}。
%    \begin{macrocode}
\begingroup
\expandafter\ifx\csname ProvidesFile\endcsname\relax
  \long\def\x#1\ProvidesFile#2[#3]{%
    #1%
    \immediate\write-1{File: #2 #3}%
    \expandafter\xdef\csname ver@#2\endcsname{#3}}
  \expandafter\x%
\fi
\endgroup
%    \end{macrocode}
% \end{macro}
%
% 文件标识信息。
%    \begin{macrocode}
%&lt;adobe&gt;\ProvidesFile{ctex-zhmap-adobe.tex}%
%&lt;adobe&gt;  [2022/07/14 v2.5.10 Adobe font map loader for DVIPDFMx (CTEX)]
%&lt;fandol&gt;\ProvidesFile{ctex-zhmap-fandol.tex}%
%&lt;fandol&gt;  [2022/07/14 v2.5.10 Fandol font map loader for DVIPDFMx (CTEX)]
%&lt;founder&gt;\ProvidesFile{ctex-zhmap-founder.tex}%
%&lt;founder&gt;  [2022/07/14 v2.5.10 Founder font map loader for pdfTeX and DVIPDFMx (CTEX)]
%&lt;mac&gt;\ProvidesFile{ctex-zhmap-mac.tex}%
%&lt;mac&gt;  [2022/07/14 v2.5.10 Mac font map loader for DVIPDFMx (CTEX)]
%&lt;ubuntu&gt;\ProvidesFile{ctex-zhmap-ubuntu.tex}%
%&lt;ubuntu&gt;  [2022/07/14 v2.5.10 Ubuntu font map loader for DVIPDFMx (CTEX)]
%&lt;windows&gt;\ProvidesFile{ctex-zhmap-windows.tex}%
%&lt;windows&gt;  [2022/07/14 v2.5.10 Windows font map loader for pdfTeX and DVIPDFMx (CTEX)]
%    \end{macrocode}
%
% \paragraph{\pkg{ctex-zhmap-adobe.tex}}
%
%    \begin{macrocode}
%&lt;*adobe&gt;
\ifzhmappdf
%% pdfTeX does not support OTF fonts
\else
  \special{pdf:mapline gbk@UGBK@          UniGB-UTF16-H AdobeSongStd-Light.otf}
  \special{pdf:mapline gbksong@UGBK@      UniGB-UTF16-H AdobeSongStd-Light.otf}
  \special{pdf:mapline gbkkai@UGBK@       UniGB-UTF16-H AdobeKaitiStd-Regular.otf}
  \special{pdf:mapline gbkhei@UGBK@       UniGB-UTF16-H AdobeHeitiStd-Regular.otf}
  \special{pdf:mapline gbkfs@UGBK@        UniGB-UTF16-H AdobeFangsongStd-Regular.otf}
  \special{pdf:mapline cyberb@Unicode@    UniGB-UTF16-H AdobeSongStd-Light.otf}
  \special{pdf:mapline unisong@Unicode@   UniGB-UTF16-H AdobeSongStd-Light.otf}
  \special{pdf:mapline unikai@Unicode@    UniGB-UTF16-H AdobeKaitiStd-Regular.otf}
  \special{pdf:mapline unihei@Unicode@    UniGB-UTF16-H AdobeHeitiStd-Regular.otf}
  \special{pdf:mapline unifs@Unicode@     UniGB-UTF16-H AdobeFangsongStd-Regular.otf}
  \special{pdf:mapline gbksongsl@UGBK@    UniGB-UTF16-H AdobeSongStd-Light.otf       -s .167}
  \special{pdf:mapline gbkkaisl@UGBK@     UniGB-UTF16-H AdobeKaitiStd-Regular.otf    -s .167}
  \special{pdf:mapline gbkheisl@UGBK@     UniGB-UTF16-H AdobeHeitiStd-Regular.otf    -s .167}
  \special{pdf:mapline gbkfssl@UGBK@      UniGB-UTF16-H AdobeFangsongStd-Regular.otf -s .167}
  \special{pdf:mapline unisongsl@Unicode@ UniGB-UTF16-H AdobeSongStd-Light.otf       -s .167}
  \special{pdf:mapline unikaisl@Unicode@  UniGB-UTF16-H AdobeKaitiStd-Regular.otf    -s .167}
  \special{pdf:mapline uniheisl@Unicode@  UniGB-UTF16-H AdobeHeitiStd-Regular.otf    -s .167}
  \special{pdf:mapline unifssl@Unicode@   UniGB-UTF16-H AdobeFangsongStd-Regular.otf -s .167}
\fi
%&lt;/adobe&gt;
%    \end{macrocode}
%
% \paragraph{\pkg{ctex-zhmap-fandol.tex}}
%
%    \begin{macrocode}
%&lt;*fandol&gt;
\ifzhmappdf
%% pdfTeX does not support OTF fonts
\else
  \special{pdf:mapline gbk@UGBK@          UniGB-UTF16-H FandolSong-Regular.otf}
  \special{pdf:mapline gbksong@UGBK@      UniGB-UTF16-H FandolSong-Regular.otf}
  \special{pdf:mapline gbkkai@UGBK@       UniGB-UTF16-H FandolKai-Regular.otf}
  \special{pdf:mapline gbkhei@UGBK@       UniGB-UTF16-H FandolHei-Regular.otf}
  \special{pdf:mapline gbkfs@UGBK@        UniGB-UTF16-H FandolFang-Regular.otf}
  \special{pdf:mapline cyberb@Unicode@    UniGB-UTF16-H FandolSong-Regular.otf}
  \special{pdf:mapline unisong@Unicode@   UniGB-UTF16-H FandolSong-Regular.otf}
  \special{pdf:mapline unikai@Unicode@    UniGB-UTF16-H FandolKai-Regular.otf}
  \special{pdf:mapline unihei@Unicode@    UniGB-UTF16-H FandolHei-Regular.otf}
  \special{pdf:mapline unifs@Unicode@     UniGB-UTF16-H FandolFang-Regular.otf}
  \special{pdf:mapline gbksongsl@UGBK@    UniGB-UTF16-H FandolSong-Regular.otf -s .167}
  \special{pdf:mapline gbkkaisl@UGBK@     UniGB-UTF16-H FandolKai-Regular.otf  -s .167}
  \special{pdf:mapline gbkheisl@UGBK@     UniGB-UTF16-H FandolHei-Regular.otf  -s .167}
  \special{pdf:mapline gbkfssl@UGBK@      UniGB-UTF16-H FandolFang-Regular.otf -s .167}
  \special{pdf:mapline unisongsl@Unicode@ UniGB-UTF16-H FandolSong-Regular.otf -s .167}
  \special{pdf:mapline unikaisl@Unicode@  UniGB-UTF16-H FandolKai-Regular.otf  -s .167}
  \special{pdf:mapline uniheisl@Unicode@  UniGB-UTF16-H FandolHei-Regular.otf  -s .167}
  \special{pdf:mapline unifssl@Unicode@   UniGB-UTF16-H FandolFang-Regular.otf -s .167}
\fi
%&lt;/fandol&gt;
%    \end{macrocode}
%
% \paragraph{\pkg{ctex-zhmap-founder.tex}}
%
%    \begin{macrocode}
%&lt;*founder&gt;
\ifzhmappdf
  \pdfmapline{=gbk@UGBK@          &lt;FZSSK.TTF}
  \pdfmapline{=gbksong@UGBK@      &lt;FZSSK.TTF}
  \pdfmapline{=gbkkai@UGBK@       &lt;FZKTK.TTF}
  \pdfmapline{=gbkhei@UGBK@       &lt;FZHTK.TTF}
  \pdfmapline{=gbkfs@UGBK@        &lt;FZFSK.TTF}
  \pdfmapline{=gbkli@UGBK@        &lt;FZLSK.TTF}
  \pdfmapline{=gbkyou@UGBK@       &lt;FZY1K.TTF}
  \pdfmapline{=cyberb@Unicode@    &lt;FZSSK.TTF}
  \pdfmapline{=unisong@Unicode@   &lt;FZSSK.TTF}
  \pdfmapline{=unikai@Unicode@    &lt;FZKTK.TTF}
  \pdfmapline{=unihei@Unicode@    &lt;FZHTK.TTF}
  \pdfmapline{=unifs@Unicode@     &lt;FZFSK.TTF}
  \pdfmapline{=unili@Unicode@     &lt;FZLSK.TTF}
  \pdfmapline{=uniyou@Unicode@    &lt;FZY1K.TTF}
  \pdfmapline{=gbksongsl@UGBK@    &lt;FZSSK.TTF}
  \pdfmapline{=gbkkaisl@UGBK@     &lt;FZKTK.TTF}
  \pdfmapline{=gbkheisl@UGBK@     &lt;FZHTK.TTF}
  \pdfmapline{=gbkfssl@UGBK@      &lt;FZFSK.TTF}
  \pdfmapline{=gbklisl@UGBK@      &lt;FZLSK.TTF}
  \pdfmapline{=gbkyousl@UGBK@     &lt;FZY1K.TTF}
  \pdfmapline{=unisongsl@Unicode@ &lt;FZSSK.TTF}
  \pdfmapline{=unikaisl@Unicode@  &lt;FZKTK.TTF}
  \pdfmapline{=uniheisl@Unicode@  &lt;FZHTK.TTF}
  \pdfmapline{=unifssl@Unicode@   &lt;FZFSK.TTF}
  \pdfmapline{=unilisl@Unicode@   &lt;FZLSK.TTF}
  \pdfmapline{=uniyousl@Unicode@  &lt;FZY1K.TTF}
\else
  \special{pdf:mapline gbk@UGBK@          unicode FZSSK.TTF}
  \special{pdf:mapline gbksong@UGBK@      unicode FZSSK.TTF}
  \special{pdf:mapline gbkkai@UGBK@       unicode FZKTK.TTF}
  \special{pdf:mapline gbkhei@UGBK@       unicode FZHTK.TTF}
  \special{pdf:mapline gbkfs@UGBK@        unicode FZFSK.TTF}
  \special{pdf:mapline gbkli@UGBK@        unicode FZLSK.TTF}
  \special{pdf:mapline gbkyou@UGBK@       unicode FZY1K.TTF}
  \special{pdf:mapline cyberb@Unicode@    unicode FZSSK.TTF}
  \special{pdf:mapline unisong@Unicode@   unicode FZSSK.TTF}
  \special{pdf:mapline unikai@Unicode@    unicode FZKTK.TTF}
  \special{pdf:mapline unihei@Unicode@    unicode FZHTK.TTF}
  \special{pdf:mapline unifs@Unicode@     unicode FZFSK.TTF}
  \special{pdf:mapline unili@Unicode@     unicode FZLSK.TTF}
  \special{pdf:mapline uniyou@Unicode@    unicode FZY1K.TTF}
  \special{pdf:mapline gbksongsl@UGBK@    unicode FZSSK.TTF -s .167}
  \special{pdf:mapline gbkkaisl@UGBK@     unicode FZKTK.TTF -s .167}
  \special{pdf:mapline gbkheisl@UGBK@     unicode FZHTK.TTF -s .167}
  \special{pdf:mapline gbkfssl@UGBK@      unicode FZFSK.TTF -s .167}
  \special{pdf:mapline gbklisl@UGBK@      unicode FZLSK.TTF -s .167}
  \special{pdf:mapline gbkyousl@UGBK@     unicode FZY1K.TTF -s .167}
  \special{pdf:mapline unisongsl@Unicode@ unicode FZSSK.TTF -s .167}
  \special{pdf:mapline unikaisl@Unicode@  unicode FZKTK.TTF -s .167}
  \special{pdf:mapline uniheisl@Unicode@  unicode FZHTK.TTF -s .167}
  \special{pdf:mapline unifssl@Unicode@   unicode FZFSK.TTF -s .167}
  \special{pdf:mapline unilisl@Unicode@   unicode FZLSK.TTF -s .167}
  \special{pdf:mapline uniyousl@Unicode@  unicode FZY1K.TTF -s .167}
\fi
%&lt;/founder&gt;
%    \end{macrocode}
%
% \paragraph{\pkg{ctex-zhmap-mac.tex}}
%
% \changes{v2.5}{2020/01/15}{增加字体映射文件 \file{zhmacfonts.tex}。}
%
%    \begin{macrocode}
%&lt;*mac&gt;
\ifzhmappdf
%% pdfTeX does not support OTF fonts
\else
  \special{pdf:mapline gbk@UGBK@          UniGB-UTF16-H :3:Songti.ttc}
  \special{pdf:mapline gbksong@UGBK@      UniGB-UTF16-H :3:Songti.ttc}
  \special{pdf:mapline gbkkai@UGBK@       UniGB-UTF16-H :0:Kaiti.ttc}
  \special{pdf:mapline gbkhei@UGBK@       unicode       :2:PingFang.ttc}
  \special{pdf:mapline gbkfs@UGBK@        unicode       STFANGSO.ttf}
  \special{pdf:mapline gbkli@UGBK@        UniGB-UTF16-H :0:Baoli.ttc}
  \special{pdf:mapline gbkyou@UGBK@       UniGB-UTF16-H :4:Yuanti.ttc}
  \special{pdf:mapline cyberb@Unicode@    UniGB-UTF16-H :3:Songti.ttc}
  \special{pdf:mapline unisong@Unicode@   UniGB-UTF16-H :3:Songti.ttc}
  \special{pdf:mapline unikai@Unicode@    UniGB-UTF16-H :0:Kaiti.ttc}
  \special{pdf:mapline unihei@Unicode@    unicode       :2:PingFang.ttc}
  \special{pdf:mapline unifs@Unicode@     unicode       STFANGSO.ttf}
  \special{pdf:mapline unili@Unicode@     UniGB-UTF16-H :0:Baoli.ttc}
  \special{pdf:mapline uniyou@Unicode@    UniGB-UTF16-H :4:Yuanti.ttc}
  \special{pdf:mapline gbksongsl@UGBK@    UniGB-UTF16-H :3:Songti.ttc   -s .167}
  \special{pdf:mapline gbkkaisl@UGBK@     UniGB-UTF16-H :0:Kaiti.ttc    -s .167}
  \special{pdf:mapline gbkheisl@UGBK@     unicode       :2:PingFang.ttc -s .167}
  \special{pdf:mapline gbkfssl@UGBK@      unicode       STFANGSO.ttf    -s .167}
  \special{pdf:mapline gbklisl@UGBK@      UniGB-UTF16-H :0:Baoli.ttc    -s .167}
  \special{pdf:mapline gbkyousl@UGBK@     UniGB-UTF16-H :4:Yuanti.ttc   -s .167}
  \special{pdf:mapline unisongsl@Unicode@ UniGB-UTF16-H :3:Songti.ttc   -s .167}
  \special{pdf:mapline unikaisl@Unicode@  UniGB-UTF16-H :0:Kaiti.ttc    -s .167}
  \special{pdf:mapline uniheisl@Unicode@  unicode       :2:PingFang.ttc -s .167}
  \special{pdf:mapline unifssl@Unicode@   unicode       STFANGSO.ttf    -s .167}
  \special{pdf:mapline unilisl@Unicode@   UniGB-UTF16-H :0:Baoli.ttc    -s .167}
  \special{pdf:mapline uniyousl@Unicode@  UniGB-UTF16-H :4:Yuanti.ttc   -s .167}
\fi
%&lt;/mac&gt;
%    \end{macrocode}
%
% \paragraph{\pkg{ctex-zhmap-ubuntu.tex}}
%
%    \begin{macrocode}
%&lt;*ubuntu&gt;
\ifzhmappdf
%% pdfTeX does not support OTF fonts
\else
  \special{pdf:mapline gbk@UGBK@          unicode :2:NotoSerifCJK-Regular.ttc}
  \special{pdf:mapline gbksong@UGBK@      unicode :2:NotoSerifCJK-Regular.ttc}
  \special{pdf:mapline gbkkai@UGBK@       unicode gkai00mp.ttf}
  \special{pdf:mapline gbkhei@UGBK@       unicode :2:NotoSansCJK-Regular.ttc}
  \special{pdf:mapline gbkfs@UGBK@        unicode :2:NotoSerifCJK-Regular.ttc}
  \special{pdf:mapline cyberb@Unicode@    unicode :2:NotoSerifCJK-Regular.ttc}
  \special{pdf:mapline unisong@Unicode@   unicode :2:NotoSerifCJK-Regular.ttc}
  \special{pdf:mapline unikai@Unicode@    unicode gkai00mp.ttf}
  \special{pdf:mapline unihei@Unicode@    unicode :2:NotoSansCJK-Regular.ttc}
  \special{pdf:mapline unifs@Unicode@     unicode :2:NotoSerifCJK-Regular.ttc}
  \special{pdf:mapline gbksongsl@UGBK@    unicode :2:NotoSerifCJK-Regular.ttc -s .167}
  \special{pdf:mapline gbkkaisl@UGBK@     unicode gkai00mp.ttf                -s .167}
  \special{pdf:mapline gbkheisl@UGBK@     unicode :2:NotoSansCJK-Regular.ttc  -s .167}
  \special{pdf:mapline gbkfssl@UGBK@      unicode :2:NotoSerifCJK-Regular.ttc -s .167}
  \special{pdf:mapline unisongsl@Unicode@ unicode :2:NotoSerifCJK-Regular.ttc -s .167}
  \special{pdf:mapline unikaisl@Unicode@  unicode gkai00mp.ttf                -s .167}
  \special{pdf:mapline uniheisl@Unicode@  unicode :2:NotoSansCJK-Regular.ttc  -s .167}
  \special{pdf:mapline unifssl@Unicode@   unicode :2:NotoSerifCJK-Regular.ttc -s .167}
\fi
%&lt;/ubuntu&gt;
%    \end{macrocode}
%
% \paragraph{\pkg{ctex-zhmap-windows.tex}}
%
%    \begin{macrocode}
%&lt;*windows&gt;
\ifzhmappdf
  \pdfmapline{=gbk@UGBK@          &lt;simsun.ttc}
  \pdfmapline{=gbksong@UGBK@      &lt;simsun.ttc}
  \pdfmapline{=gbkkai@UGBK@       &lt;simkai.ttf}
  \pdfmapline{=gbkhei@UGBK@       &lt;simhei.ttf}
  \pdfmapline{=gbkfs@UGBK@        &lt;simfang.ttf}
  \pdfmapline{=gbkli@UGBK@        &lt;simli.ttf}
  \pdfmapline{=gbkyou@UGBK@       &lt;simyou.ttf}
  \pdfmapline{=cyberb@Unicode@    &lt;simsun.ttc}
  \pdfmapline{=unisong@Unicode@   &lt;simsun.ttc}
  \pdfmapline{=unikai@Unicode@    &lt;simkai.ttf}
  \pdfmapline{=unihei@Unicode@    &lt;simhei.ttf}
  \pdfmapline{=unifs@Unicode@     &lt;simfang.ttf}
  \pdfmapline{=unili@Unicode@     &lt;simli.ttf}
  \pdfmapline{=uniyou@Unicode@    &lt;simyou.ttf}
  \pdfmapline{=gbksongsl@UGBK@    &lt;simsun.ttc}
  \pdfmapline{=gbkkaisl@UGBK@     &lt;simkai.ttf}
  \pdfmapline{=gbkheisl@UGBK@     &lt;simhei.ttf}
  \pdfmapline{=gbkfssl@UGBK@      &lt;simfang.ttf}
  \pdfmapline{=gbklisl@UGBK@      &lt;simli.ttf}
  \pdfmapline{=gbkyousl@UGBK@     &lt;simyou.ttf}
  \pdfmapline{=unisongsl@Unicode@ &lt;simsun.ttc}
  \pdfmapline{=unikaisl@Unicode@  &lt;simkai.ttf}
  \pdfmapline{=uniheisl@Unicode@  &lt;simhei.ttf}
  \pdfmapline{=unifssl@Unicode@   &lt;simfang.ttf}
  \pdfmapline{=unilisl@Unicode@   &lt;simli.ttf}
  \pdfmapline{=uniyousl@Unicode@  &lt;simyou.ttf}
\else
  \special{pdf:mapline gbk@UGBK@          unicode :0:simsun.ttc -v 50}
  \special{pdf:mapline gbksong@UGBK@      unicode :0:simsun.ttc -v 50}
  \special{pdf:mapline gbkkai@UGBK@       unicode simkai.ttf    -v 70}
  \special{pdf:mapline gbkhei@UGBK@       unicode simhei.ttf    -v 150}
  \special{pdf:mapline gbkfs@UGBK@        unicode simfang.ttf   -v 50}
  \special{pdf:mapline gbkli@UGBK@        unicode simli.ttf     -v 150}
  \special{pdf:mapline gbkyou@UGBK@       unicode simyou.ttf    -v 60}
  \special{pdf:mapline cyberb@Unicode@    unicode :0:simsun.ttc -v 50}
  \special{pdf:mapline unisong@Unicode@   unicode :0:simsun.ttc -v 50}
  \special{pdf:mapline unikai@Unicode@    unicode simkai.ttf    -v 70}
  \special{pdf:mapline unihei@Unicode@    unicode simhei.ttf    -v 150}
  \special{pdf:mapline unifs@Unicode@     unicode simfang.ttf   -v 50}
  \special{pdf:mapline unili@Unicode@     unicode simli.ttf     -v 150}
  \special{pdf:mapline uniyou@Unicode@    unicode simyou.ttf    -v 60}
  \special{pdf:mapline gbksongsl@UGBK@    unicode :0:simsun.ttc -v 50  -s .167}
  \special{pdf:mapline gbkkaisl@UGBK@     unicode simkai.ttf    -v 70  -s .167}
  \special{pdf:mapline gbkheisl@UGBK@     unicode simhei.ttf    -v 150 -s .167}
  \special{pdf:mapline gbkfssl@UGBK@      unicode simfang.ttf   -v 50  -s .167}
  \special{pdf:mapline gbklisl@UGBK@      unicode simli.ttf     -v 150 -s .167}
  \special{pdf:mapline gbkyousl@UGBK@     unicode simyou.ttf    -v 60  -s .167}
  \special{pdf:mapline unisongsl@Unicode@ unicode :0:simsun.ttc -v 50  -s .167}
  \special{pdf:mapline unikaisl@Unicode@  unicode simkai.ttf    -v 70  -s .167}
  \special{pdf:mapline uniheisl@Unicode@  unicode simhei.ttf    -v 150 -s .167}
  \special{pdf:mapline unifssl@Unicode@   unicode simfang.ttf   -v 50  -s .167}
  \special{pdf:mapline unilisl@Unicode@   unicode simli.ttf     -v 150 -s .167}
  \special{pdf:mapline uniyousl@Unicode@  unicode simyou.ttf    -v 60  -s .167}
\fi
%&lt;/windows&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
\ctex@zhmap@endinput
%&lt;/zhmap&gt;
%    \end{macrocode}
%
% \subsubsection{制作 \texttt{spa} 文件}
%
% \changes{v2.5.2}{2020/05/05}{\file{ctexmakespa.tex} 更名为 \file{ctex-spa-make.tex}。}
% \changes{v2.5.2}{2020/05/05}{\file{ctexspamacro.tex} 更名为 \file{ctex-spa-macro.tex}。}
%
% 我们通过 \XeTeX{} 的 \tn{XeTeXglyphbounds} 取得字体中标点符号的边界信息，为
% \pkg{CJKpunct} 宏包制作 \file{spa}。
%
%    \begin{macrocode}
%&lt;*spa&gt;
%&lt;*macro&gt;
\input expl3-generic %
\ExplSyntaxOn
\sys_if_engine_xetex:F
  {
    \msg_new:nnn { ctex } { xetex }
      { XeTeX~is~required~to~compile~this~document! }
    \msg_fatal:nn { ctex } { xetex }
  }
%    \end{macrocode}
%
% \pkg{CJKpunct} 定义的标点符号是：
% \begin{verbatim}
%   ‘“「『〔（［｛〈《〖【
%   —…、。，．：；！？％〕）］｝〉》〗】’”」』
% \end{verbatim}
% 注意顺序不能改变。
%    \begin{macrocode}
\seq_const_from_clist:Nn \c_@@_punct_seq
  {
    "2018 , "201C , "300C , "300E , "3014 , "FF08 , "FF3B , "FF5B ,
    "3008 , "300A , "3016 , "3010 ,
    "2014 , "2026 , "3001 , "3002 , "FF0C , "FF0E , "FF1A , "FF1B ,
    "FF01 , "FF1F , "FF05 , "3015 , "FF09 , "FF3D , "FF5D , "3009 ,
    "300B , "3017 , "3011 , "2019 , "201D , "300D , "300F
  }
%    \end{macrocode}
%
% \begin{macro}[int]{\ctex_make_spa:nn}
% |#1| 是 \file{spa} 文件名，|#2| 是由 CJK 族名与字体构成的逗号列表。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_make_spa:nn #1#2
  {
    \iow_open:Nn \g_@@_spa_iow {#1}
    \clist_map_inline:nn {#2}
      { \@@_write_family:nn ##1 }
    \iow_close:N \g_@@_spa_iow
  }
\iow_new:N \g_@@_spa_iow
\cs_new_eq:NN \MAKESPA \ctex_make_spa:nn
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\cs_new_protected:Npn \@@_write_family:nn #1#2
  {
    \group_begin:
      \tex_font:D \l_@@_punct_font = "#2" ~ at ~ 100 pt \scan_stop:
      \l_@@_punct_font
      \clist_clear:N \l_@@_punct_bounds_clist
      \seq_map_inline:Nn \c_@@_punct_seq
        { \exp_args:No \@@_save_bounds:n { \int_use:N \tex_XeTeXcharglyph:D ##1 } }
      \iow_now:Nx \g_@@_spa_iow
        {
          \token_to_str:N \ctexspadef {#1}
%    \end{macrocode}
% 最后这三个逗号对 \pkg{CJKpunct} 来说是必要的。
%    \begin{macrocode}
            { \l_@@_punct_bounds_clist , , , }
        }
    \group_end:
  }
\cs_new_protected:Npn \@@_save_bounds:n #1
  {
    \clist_put_right:Nx \l_@@_punct_bounds_clist
      {
        \@@_calc_bounds:nn { 1 } {#1} ,
        \@@_calc_bounds:nn { 3 } {#1}
      }
  }
\clist_new:N \l_@@_punct_bounds_clist
%    \end{macrocode}
%
% \pkg{CJKpunct} 要求的格式是边界空白宽度与 1\,em 的比值的一百倍。
%    \begin{macrocode}
\cs_new:Npn \@@_calc_bounds:nn #1#2
  {
    \fp_eval:n
      {
        round
          (
            \dim_to_decimal_in_unit:nn
              { 100 \tex_XeTeXglyphbounds:D #1 ~ #2 }
              { 1 em }
          )
      }
  }
\ExplSyntaxOff
%&lt;/macro&gt;
%    \end{macrocode}
%
% 下面是 \CTeX{} 定义的一些字体。
%    \begin{macrocode}
%&lt;*make&gt;
\input ctex-spa-macro %
\MAKESPA {ctexpunct.spa}
  {
    {adobezhsong}     {AdobeSongStd-Light} ,
    {adobezhhei}      {AdobeHeitiStd-Regular} ,
    {adobezhkai}      {AdobeKaitiStd-Regular} ,
    {adobezhfs}       {AdobeFangsongStd-Regular} ,
%
    {fandolzhsong}    {FandolSong} ,
    {fandolzhsongb}   {FandolSong-Bold} ,
    {fandolzhhei}     {FandolHei} ,
    {fandolzhheib}    {FandolHei-Bold} ,
    {fandolzhkai}     {FandolKai} ,
    {fandolzhfs}      {FandolFang} ,
%
    {founderzhsong}   {FZShuSong-Z01} ,
    {founderzhsongb}  {FZXiaoBiaoSong-B05} ,
    {founderzhhei}    {FZHei-B01} ,
    {founderzhheil}   {FZXiHeiI-Z08} ,
    {founderzhkai}    {FZKai-Z03} ,
    {founderzhfs}     {FZFangSong-Z02} ,
    {founderzhli}     {FZLiShu-S01} ,
    {founderzhyou}    {FZXiYuan-M01} ,
    {founderzhyoub}   {FZZhunYuan-M02} ,
%
    {maczhsong}       {Songti SC Light} ,
    {maczhsongb}      {Songti SC Bold} ,
    {maczhhei}        {Heiti SC Medium} ,
    {maczhheil}       {Heiti SC Light} ,
    {maczhkai}        {Kaiti SC} ,
    {maczhkaib}       {Kaiti SC Bold} ,
    {maczhfs}         {STFangsong} ,
    {maczhli}         {Baoli SC} ,
    {maczhyou}        {Yuanti SC Light} ,
    {maczhyoub}       {Yuanti SC Regular} ,
    {maczhpf}         {PingFang SC} ,
    {maczhpfb}        {PingFang SC Semibold} ,
%
    {ubuntuzhsong}    {Noto Serif CJK SC} ,
    {ubuntuzhsongb}   {Noto Serif CJK SC Bold} ,
    {ubuntuzhhei}     {Noto Sans CJK SC} ,
    {ubuntuzhheib}    {Noto Sans CJK SC Bold} ,
    {ubuntuzhkai}     {AR PL KaitiM GB} ,
%
    {windowszhsong}   {SimSun} ,
    {windowszhhei}    {SimHei} ,
    {windowszhkai}    {KaiTi} ,
    {windowszhfs}     {FangSong} ,
    {windowszhli}     {LiSu} ,
    {windowszhyou}    {YouYuan} ,
    {windowszhyahei}  {Microsoft YaHei} ,
    {windowszhyaheib} {Microsoft YaHei Bold}
  }
\primitive\end
%&lt;/make&gt;
%&lt;/spa&gt;
%    \end{macrocode}
%
% \subsection{\pkg{translator} 宏包的中文字典}
%
%    \begin{macrocode}
%&lt;*dict&gt;
%    \end{macrocode}
%
% \changes{v2.4}{2016/02/19}{提供 \pkg{translator} 宏包的中文定理名称翻译。}
%
% 包括 \pkg{ChineseGBK} 和 \pkg{ChineseUTF8} 两种形式，目前只翻译 \pkg{beamer}
% 宏包需要的定理环境名称。
%
%    \begin{macrocode}
%&lt;*theorem&gt;
\providetranslation{Comments}{评论}
\providetranslation{comments}{评论}
\providetranslation{Comment}{评论}
\providetranslation{comment}{评论}
\providetranslation{Corollaries}{推论}
\providetranslation{corollaries}{推论}
\providetranslation{Corollary}{推论}
\providetranslation{corollary}{推论}
\providetranslation{Definitions}{定义}
\providetranslation{definitions}{定义}
\providetranslation{Definition}{定义}
\providetranslation{definition}{定义}
\providetranslation{Examples}{例}
\providetranslation{examples}{例}
\providetranslation{Example}{例}
\providetranslation{example}{例}
\providetranslation{Exercises}{练习}
\providetranslation{exercises}{练习}
\providetranslation{Exercise}{练习}
\providetranslation{exercise}{练习}
\providetranslation{Facts}{事实}
\providetranslation{facts}{事实}
\providetranslation{Fact}{事实}
\providetranslation{fact}{事实}
\providetranslation{Key Lemmas}{关键引理}
\providetranslation{key lemmas}{关键引理}
\providetranslation{Key Lemma}{关键引理}
\providetranslation{key lemma}{关键引理}
\providetranslation{Key Observations}{关键观察}
\providetranslation{key observations}{关键观察}
\providetranslation{Key Observation}{关键观察}
\providetranslation{key observation}{关键观察}
\providetranslation{Lemmas}{引理}
\providetranslation{lemmas}{引理}
\providetranslation{Lemma}{引理}
\providetranslation{lemma}{引理}
\providetranslation{Main Theorems}{主要定理}
\providetranslation{main theorems}{主要定理}
\providetranslation{Main Theorem}{主要定理}
\providetranslation{main theorem}{主要定理}
\providetranslation{Observations}{观察}
\providetranslation{observations}{观察}
\providetranslation{Observation}{观察}
\providetranslation{observation}{观察}
\providetranslation{Problems}{问题}
\providetranslation{problems}{问题}
\providetranslation{Problem}{问题}
\providetranslation{problem}{问题}
\providetranslation{Proofs}{证明}
\providetranslation{proofs}{证明}
\providetranslation{Proof}{证明}
\providetranslation{proof}{证明}
\providetranslation{Proof Sketch}{证明提要}
\providetranslation{Proof sketch}{证明提要}
\providetranslation{proof sketch}{证明提要}
\providetranslation{Proof Sketches}{证明提要}
\providetranslation{Proof sketches}{证明提要}
\providetranslation{proof sketches}{证明提要}
\providetranslation{Sketch of Proof}{证明提要}
\providetranslation{Sketch of Proofs}{证明提要}
\providetranslation{Sketch of proof}{证明提要}
\providetranslation{Sketch of proofs}{证明提要}
\providetranslation{sketch of proof}{证明提要}
\providetranslation{sketch of proofs}{证明提要}
\providetranslation{Propositions}{命题}
\providetranslation{propositions}{命题}
\providetranslation{Proposition}{命题}
\providetranslation{proposition}{命题}
\providetranslation{Remarks}{注}
\providetranslation{remarks}{注}
\providetranslation{Remark}{注}
\providetranslation{remark}{注}
\providetranslation{Solutions}{解}
\providetranslation{solutions}{解}
\providetranslation{Solution}{解}
\providetranslation{solution}{解}
\providetranslation{Theorems}{定理}
\providetranslation{theorems}{定理}
\providetranslation{Theorem}{定理}
\providetranslation{theorem}{定理}
%&lt;/theorem&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/dict&gt;
%    \end{macrocode}
%
% \subsection{\pkg{ctexcap} 宏包}
%
%    \begin{macrocode}
%&lt;*ctexcap&gt;
%    \end{macrocode}
%
% \pkg{ctexcap} 是过时宏包。
%    \begin{macrocode}
\clist_new:N \l_@@_ctexcap_options_clist
\clist_set:Nx \l_@@_ctexcap_options_clist
  { \exp_not:v { opt@ \@currname . \@currext } , heading }
\msg_new:nnn { ctexcap } { deprecated }
  {
    Package~`ctexcap'~is~deprecated.\\
    Please~use~package~`ctex'~with~option~`#1'~instead: \\\\
    \iow_indent:n { \token_to_str:N \usepackage [#1] \{ ctex \} } \\
  }
\msg_warning:nnx { ctexcap } { deprecated }
  { \clist_use:Nn \l_@@_ctexcap_options_clist { , ~ } }
%    \end{macrocode}
%
% \pkg{ctexcap} 是默认打开 \opt{heading} 选项的 \pkg{ctex}。
%    \begin{macrocode}
\PassOptionsToPackage { heading = true } { ctexcap }
\RequirePackageWithOptions { ctex }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/ctexcap&gt;
%    \end{macrocode}
%
%
% \subsection{\pkg{ctexhook} 宏包}
%
% \changes{v2.2}{2015/06/26}{将文档开头和宏包末尾钩子提取到 \pkg{ctexhook} 宏包中。}
% \changes{v2.5}{2020/04/21}{增加宏包开头钩子。}
% \changes{v2.5.4}{2020/08/02}{兼容 \LaTeX \ 2020/10/01 的钩子机制。}
%
%    \begin{macrocode}
%&lt;*ctexhook&gt;
%    \end{macrocode}
%
% \begin{macro}[int]{\ctex_if_format_at_least:nTF}
%  与 \tn{IfFormatAtLeastTF} 同义。
%    \begin{macrocode}
\cs_new:Npn \ctex_if_format_at_least:nTF
  { \@ifl@t@r \fmtversion }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.7}{2021/06/12}{重新应用 \pkg{l3cctab}。}
%
% \begin{macro}[int]{\ctex_file_input:n,\ctex_push_file:,\ctex_pop_file:}
% 输入文件，关闭 \LaTeXiii 语法环境，并设置 |@| 为字母类，利用 \pkg{l3cctab} 实现。
% 我们使用 \cs{file_input:n} 而不是 \LaTeXe \ 的 \tn{input} 或者 \tn{InputIfFileExists}
% 载入文件，因此 \LaTeXe \ 的文件钩子都\emph{无效}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_file_input:n #1
  {
    \ctex_push_file:
      \file_input:n {#1}
    \ctex_pop_file:
  }
\bool_if_exist:NTF \l__kernel_expl_bool
  {
    \cs_new_protected:Npn \ctex_push_file:
      {
        \seq_gpush:Nx \g_@@_expl_status_seq
          { \bool_if:NTF \l__kernel_expl_bool { 1 } { 0 } }
        \bool_set_false:N \l__kernel_expl_bool
        \cctab_begin:N \c_@@_package_cctab
      }
    \cs_new_protected:Npn \ctex_pop_file:
      {
        \cctab_end:
        \seq_gpop:NN \g_@@_expl_status_seq \l_@@_expl_status_tl
        \int_if_odd:nTF { \l_@@_expl_status_tl }
          { \bool_set_true:N  \l__kernel_expl_bool }
          { \bool_set_false:N \l__kernel_expl_bool }
      }
    \tl_new:N \l_@@_expl_status_tl
    \seq_new:N \g_@@_expl_status_seq
  }
  {
    \cs_new_protected:Npn \ctex_push_file:
      { \cctab_begin:N \c_@@_package_cctab }
    \cs_new_protected:Npn \ctex_pop_file:
      { \cctab_end: }
  }
\cctab_const:Nn \c_@@_package_cctab
  {
    \cctab_select:N \c_document_cctab
    \char_set_catcode_letter:n { 64 }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.7}{2021/06/09}{使用 \tn{disable@package@load} 禁止宏包载入。}
%
% \begin{macro}[int]{\ctex_disable_package:n}
% 禁止宏包载入。采用 \LaTeX \ 2020-10-01 提供的 \tn{disable@package@load} 实现，
% 否则采用传统方式：预定义 |\ver@|\meta{package}|.sty| 标识符。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_disable_package:n #1
  {
    \@ifpackageloaded {#1}
      { \msg_error:nnxx }
      { \@@_disable_package_aux:nnnn }
      { ctexhook } { disable-package } {#1} { \@currname }
  }
\cs_new_protected:Npx \@@_disable_package_aux:nnnn #1#2#3#4
  {
    \cs_if_exist:NTF \disable@package@load
      {
        \exp_args:Nnx \exp_not:N \disable@package@load {#3}
          { \msg_warning:nnnn {#1} {#2} {#3} {#4} }
      }
      { \tl_const:cn { ver@ #3 . \exp_not:N \@pkgextension } { 9999/99/99 } }
  }
\msg_new:nnn { ctexhook } { disable-package }
  { Package~`#1'~can~not~be~loaded~with~`#2'. }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_replace_package:nn}
% 替换宏包。采用 \LaTeX \ 2020-10-01 提供的 \tn{declare@file@substitution} 实现，
% 否则给出无效警告。
%    \begin{macrocode}
\ctex_if_format_at_least:nTF { 2020/10/01 }
  {
    \cs_new_protected:Npn \ctex_replace_package:nn #1#2
      {
        \declare@file@substitution
          { #1 . \@pkgextension }
          { #2 . \@pkgextension }
      }
  }
  {
    \cs_new_protected:Npn \ctex_replace_package:nn
      { \msg_warning:nnnn { ctexhook } { replace-package-invalid } }
    \msg_new:nnn { ctexhook } { replace-package-invalid }
      {
        \token_to_str:N \ctex_replace_package:nn \{#1\}\{#2\}~is~invalid~
        before~LaTeX~2020-10-01.
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_at_begin_package:nn}
% 如果宏包已经被载入，则钩子无效，给出警告。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_at_begin_package:nn #1
  {
    \@ifpackageloaded {#1}
      { \@@_package_loaded_warning:nn {#1} }
      { \ctex_gadd_package_hook:nnn { before } {#1} }
  }
\cs_new_protected:Npn \@@_package_loaded_warning:nn #1#2
  { \msg_warning:nnx { ctexhook } { invalid-hook } {#1} }
\msg_new:nnn { ctexhook } { invalid-hook }
  {
    Package~`#1'~is~loaded. \\
    \token_to_str:N \ctex_at_begin_package:nn \{#1\}\{...\}~is~invalid.
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_at_end_package:nn}
% 与 \pkg{filehook} 的 \tn{AtEndOfPackageFile*} 类似，如果原来没有在载入宏包则
% 在宏包末尾执行语句，否则立即执行。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_at_end_package:nn #1
  {
    \@ifpackageloaded {#1}
      { \use:n }
      { \ctex_gadd_package_hook:nnn { after } {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v2.5.6}{2021/02/16}{使用正确的导言区末尾钩子。}
% \changes{v2.5.8}{2021/11/18}{兼容 \LaTeX \ 2021/11/15。}
%
% \LaTeX \ 2020/10/01 开始提供常用钩子管理机制。在新机制下，我们只需要做简单的包装。
%    \begin{macrocode}
\ctex_if_format_at_least:nTF { 2020/10/01 }
  {
    \cs_new_protected:Npx \ctex_gadd_ltxhook:nn #1
      { \hook_gput_code:nnn {#1} { \c_novalue_tl } }
    \cs_new_protected:Npn \ctex_at_end_preamble:n
      { \ctex_gadd_ltxhook:nn { begindocument/before } }
    \cs_new_protected:Npn \ctex_after_end_preamble:n
      { \ctex_gadd_ltxhook:nn { begindocument/end } }
    \cs_new_protected:Npx \ctex_gadd_package_hook:nnn #1#2
      {
        \ctex_if_format_at_least:nTF { 2021/11/15 }
          { \ctex_gadd_ltxhook:nn { package/#2/#1 } }
          { \ctex_gadd_ltxhook:nn { package/#1/#2 } }
      }
    \file_input_stop:
  }
  { }
%    \end{macrocode}
%
% 对于 \LaTeX \ 2020/10/01 之前的版本，需要自行补丁。
%
% \begin{macro}[int]{\ctex_at_end_preamble:n,\ctex_after_end_preamble:n}
% 实现 \pkg{etoolbox} 宏包的 \tn{AtEndPreamble} 和 \tn{AfterEndPreamble}。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_at_end_preamble:n
  { \tl_gput_right:Nn \g_@@_end_preamble_hook_tl }
\cs_new_protected:Npn \ctex_after_end_preamble:n
  { \tl_gput_right:Nn \g_@@_after_end_preamble_hook_tl }
\cs_new_protected:Npn \CTEX@document@left@hook
  { \group_end: \g_@@_end_preamble_hook_tl \group_begin: }
\cs_new_protected:Npn \CTEX@document@right@hook
  { \scan_stop: \g_@@_after_end_preamble_hook_tl \tex_ignorespaces:D }
\cs_set_nopar:Npx \document
  {
    \CTEX@document@left@hook
    \exp_not:o { \document }
    \CTEX@document@right@hook
  }
\tl_new:N \g_@@_end_preamble_hook_tl
\tl_new:N \g_@@_after_end_preamble_hook_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_gadd_package_hook:nnn,
% \ctex_gadd_hook:Nn, \ctex_gadd_hook:cn}
% 给钩子附加内容。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_gadd_package_hook:nnn #1#2
  { \ctex_gadd_hook:cn { g_@@_at_ #1 _ #2 _hook_tl } }
\cs_new_protected:Npn \ctex_gadd_hook:Nn #1
  {
    \tl_if_exist:NF #1 { \tl_new:N #1 }
    \tl_gput_right:Nn #1
  }
\cs_generate_variant:Nn \ctex_gadd_hook:Nn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_use_package_hook:nn}
% 宏包钩子，只执行一次，用后清除。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_use_package_hook:nn #1#2
  {
    \group_begin: \exp_args:NNc \group_end:
    \@@_use_package_hook_aux:N { g_@@_at_ #1 _ #2 _hook_tl }
  }
\cs_new_protected:Npn \@@_use_package_hook_aux:N #1
  { \cs_if_exist_use:NT #1 { \cs_undefine:N #1 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@reset@ptions,\CTEX@reset@ptions@hook}
% \tn{@pushfilename} 内部的 \tn{@currname} 和 \tn{@currext} 保存的是
% 前一个宏包的状态，不能使用。需要对其后的 \tn{@reset@ptions} 做补丁来实现
% \cs{ctex_at_begin_package:nn} 的功能。
%    \begin{macrocode}
\tl_put_right:Nn \@reset@ptions { \CTEX@reset@ptions@hook }
\cs_new_protected:Npn \CTEX@reset@ptions@hook
  {
    \cs_if_eq:NNT \@currext \@pkgextension
      { \ctex_use_package_hook:nn { before } { \@currname } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@popfilename,\CTEX@popfilename@hook}
% 对 \tn{@popfilename} 做补丁来实现 \cs{ctex_at_end_package:nn} 的功能。
%    \begin{macrocode}
\tl_put_left:Nn \@popfilename { \CTEX@popfilename@hook }
\cs_new_protected:Npn \CTEX@popfilename@hook
  {
    \cs_if_eq:NNT \@currext \@pkgextension
      { \ctex_use_package_hook:nn { after } { \@currname } }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%&lt;/ctexhook&gt;
%    \end{macrocode}
%
%
% \subsection{\pkg{ctexpatch} 宏包}
%
% \changes{v2.2}{2015/06/23}{新增子宏包 \pkg{ctexpatch} 实现给宏打补丁功能。}
%
%    \begin{macrocode}
%&lt;*ctexpatch&gt;
%    \end{macrocode}
%
% \begin{macro}[int]{\ctex_patch_cmd_once:NnnnTF}
% 只进行第一次匹配进行替换。参数 |#2| 是宏重建时的 \tn{catcode} 设置。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_patch_cmd_once:NnnnTF #1#2
  {
    \ctex_patch_boot:NNnnTF \@@_patch_cmd:Nnnnnw #1
      { once } {#2} { \use_i:nn } { \use_ii:nn }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_patch_cmd_all:NnnnTF}
% 替换所有匹配到的文本。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_patch_cmd_all:NnnnTF #1#2
  {
    \ctex_patch_boot:NNnnTF \@@_patch_cmd:Nnnnnw #1
      { all } {#2} { \use_i:nn } { \use_ii:nn }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_patch_cmd:Nnn}
% 快捷方式，在补丁的时候关闭 \LaTeXiii{} 语法和设置 |@| 为字母类，补丁失败时给出警告。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_patch_cmd:Nnn #1
  {
    \ctex_patch_boot:NNnnTF \@@_patch_cmd:Nnnnnw #1
      { once }
      {
        \ExplSyntaxOff
        \char_set_catcode_letter:n { 64 }
      }
      { }
      { \ctex_patch_failure:N #1 }
  }
\cs_new_protected:Npn \ctex_patch_failure:N #1
  { \msg_warning:nnx { ctexpatch } { patch-failure } { \token_to_str:N #1 } }
\msg_new:nnn { ctexpatch } { patch-failure }
  { Oops!~Command~`#1'~is~NOT~patchable.\\ }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_preto_cmd:NnnTF}
% 在宏的原本定义前面增加钩子。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_preto_cmd:NnnTF #1#2
  {
    \ctex_patch_boot:NNnnTF \@@_hookto_cmd:Nnnnw #1
      { left } {#2} { \use_i:nn } { \use_ii:nn }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_appto_cmd:NnnTF}
% 在宏的原本定义后面追加钩子。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_appto_cmd:NnnTF #1#2
  {
    \ctex_patch_boot:NNnnTF \@@_hookto_cmd:Nnnnw #1
      { right } {#2} { \use_i:nn } { \use_ii:nn }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_patch_boot:NNnnTF}
% 参数记号 |#| 作为宏的参数被读入时，总是会双写，会影响随后的字符串替换。需要先
% 将它转换为普通符号。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_patch_boot:NNnnTF #1#2#3#4#5#6
  {
    \cs_set_protected:Npx \@@_patch_true:w  { \exp_not:n {#5} }
    \cs_set_protected:Npx \@@_patch_false:w { \exp_not:n {#6} }
    \group_begin:
      \char_set_catcode_other:n { 35 }
      \ctex_parse_name:NN #1 #2 {#3} {#4}
  }
\cs_new_eq:NN \@@_patch_true:w  \use_i:nn
\cs_new_eq:NN \@@_patch_false:w \use_ii:nn
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\ctex_parse_name:NN}
% \changes{v2.4}{2016/04/11}{修复宏名解析错误。}
% 用 \tn{DeclareRobustCommand} 定义的宏或者由 \tn{newcommand} 或 \tn{newrobustcmd}
% 定义的带一个可选参数的宏第一次展开的结果都不是其实际定义，实际定义被保存在另外的
% 宏中。由这些命令定义的宏的第一次展开结果可以有下面的形式（细节可查阅 \pkg{xpatch}
% 的文档）：
% \begin{verbatim}[numbers=left,gobble=4]
%   \protect␣\xaa␣␣                    % \DeclareRobustCommand\xaa[1]{...}
%   \protect␣\xab␣␣                    % \DeclareRobustCommand\xab[1][]{...}
%   \@protected@testopt␣\xac␣\\xac␣{}  % \newcommand\xac[1][]{...}
%   \@testopt␣\\xad␣{}                 % \newrobustcmd\xad[1][]{...}
%   \x@protect␣\1\protect␣\1␣␣         % \DeclareRobustCommand\1[1]{...}
%   \x@protect␣\2\protect␣\2␣␣         % \DeclareRobustCommand\2[1][]{...}
%   \@protected@testopt␣\3\\3␣{}       % \newcommand\3[1][]{...}
%   \@testopt␣\\4␣{}                   % \newrobustcmd\4[1][]{...}
% \end{verbatim}
% \pkg{ctexpatch} 的主要原理是先对宏的 \tn{meaning} 作字符串替换，然后再用
% \tn{scantokens} 来重建它。我们希望对宏的实际定义打补丁，为此需要先得到
% 对应的名字。\pkg{letltxmacro}、\pkg{show2e} 和 \pkg{xpatch} 宏包中都有
% 类似的工作。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_parse_name:NN #1#2
  { \ctex_parse_name:NNx #1#2 { \cs_to_str:N #2 } }
\group_begin:
\cs_set_protected:Npn \@@_tmp:w #1#2#3
  {
    \cs_new_protected:Npn \ctex_parse_name:NNn ##1##2##3
      {
        \bool_lazy_or:nnTF
          { \cs_if_exist_p:c { ##3 ~ } }
          { \cs_if_exist_p:c { #1##3 } }
          {
            \group_begin:
            \use:e
              {
                \group_end:
                \@@_parse_name:nNNNnN
                  { \cs_replacement_spec:N ##2 }
                  \exp_not:N ##2
                  \exp_not:c { ##3 ~ }
                  \exp_not:c { #1##3 }
              } { ##3 } ##1
          }
          { ##1##2 }
      }
    \cs_new_protected:Npn \@@_parse_name:nNNNnN ##1##2##3##4##5##6
      {
        \exp_args:Nc ##6
          {
            \str_case:nnTF {##1}
              {
                { \protect ##3 } { }
                { \x@protect ##2 \protect ##3 } { }
              }
              {
                \str_if_eq:eeTF
                  { \exp_not:n { #1@protected@ ##3 #1##3 } }
                  {
                    \exp_last_unbraced:Ne \@@_parse_name:w
                      { \cs_replacement_spec:N ##3 } #3 ~ #2 \q_stop
                  }
                  { #1##5 ~ } { ##5 ~ }
              }
              {
                \str_case:onTF { \@@_parse_name:w ##1 #3 ~ #2 \q_stop }
                  {
                    { #1@protected@ ##2 ##4 } { }
                    { #1@ ##4 } { }
                  }
                  { #1##5 } {##5}
              }
          }
      }
    \cs_new:Npn \@@_parse_name:w ##1 #3 ~ ##2 #2 ##3 \q_stop { ##1##2 }
  }
\use:e
  {
    \@@_tmp:w
      { \c_backslash_str }
      { \c_left_brace_str }
      { \tl_to_str:n { testopt } }
  }
\group_end:
\cs_generate_variant:Nn \ctex_parse_name:NNn { NNx }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_prefix_str,\l_@@_parameter_str,\l_@@_replacement_str}
% 分别保存宏的 \tn{meaning} 中的前缀、参数文本和替换文本。
%    \begin{macrocode}
\str_new:N \l_@@_prefix_str
\str_new:N \l_@@_parameter_str
\str_new:N \l_@@_replacement_str
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[int]{\ctex_get_macro_meaning:NTF}
% \begin{macro}{\@@_get_macro_meaning:w}
% 解构待补丁宏的 \tn{meaning}。若命令不是宏，则走向 |false| 分支。
%    \begin{macrocode}
\group_begin:
  \cs_set_protected:Npn \@@_tmp:w #1
    {
      \prg_new_protected_conditional:Npnn
        \ctex_get_macro_meaning:N ##1 { TF }
        {
          \exp_after:wN \@@_get_macro_meaning:w
            \token_to_meaning:N ##1 \q_mark #1 -&gt; \q_mark \q_stop
        }
      \cs_new_protected:Npn \@@_get_macro_meaning:w
          ##1 #1 ##2 -&gt; ##3 \q_mark ##4 \q_stop
        {
          \tl_if_empty:nTF { ##4 }
            { \prg_return_false: }
            {
              \str_set:Nn \l_@@_prefix_str      { ##1 }
              \str_set:Nn \l_@@_parameter_str   { ##2 }
              \str_set:Nn \l_@@_replacement_str { ##3 }
              \prg_return_true:
            }
        }
    }
  \exp_args:No \@@_tmp:w { \tl_to_str:n { macro: } }
\group_end:
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]{\ctex_if_rescanable:NnTF}
% 检查宏是否可以重建。
%    \begin{macrocode}
\cs_new_protected:Npn \ctex_if_rescanable:NnTF #1#2#3#4
  {
    \ctex_get_macro_meaning:NTF #1
      {
        \@@_patch_rebuild:Nn \@@_rebuild_cmd:w {#2}
        \cs_if_eq:NNTF #1 \@@_rebuild_cmd:w {#3} {#4}
      }
      {#4}
  }
\cs_new_eq:NN \@@_rebuild_cmd:w \prg_do_nothing:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_patch_rebuild:Nn}
% 使用 \cs{tl_rescan:nn} 来重新记号化 \tn{meaning} 字符串。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_patch_rebuild:Nn #1#2
  {
    \@@_patch_rescan:NNn \l_@@_prefix_tl      \l_@@_prefix_str      {#2}
    \@@_patch_rescan:NNn \l_@@_parameter_tl   \l_@@_parameter_str   {#2}
    \@@_patch_rescan:NNn \l_@@_replacement_tl \l_@@_replacement_str {#2}
    \use:e
      {
        \exp_not:o { \l_@@_prefix_tl } \tex_def:D \exp_not:N #1
          \exp_not:o { \l_@@_parameter_tl }
            { \exp_not:o { \l_@@_replacement_tl } }
      }
  }
\cs_new_protected:Npn \@@_patch_rescan:NNn #1#2#3
  {
    \str_if_empty:NTF #2
      { \tl_clear:N #1 }
      { \tl_set_rescan:Nno #1 {#3} {#2} }
  }
\tl_new:N \l_@@_prefix_tl
\tl_new:N \l_@@_parameter_tl
\tl_new:N \l_@@_replacement_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_patch_cmd:Nnnnnw}
% 对宏的替换文本进行字符串替换，然后重建。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_patch_cmd:Nnnnnw #1#2#3#4#5
  {
    \group_end:
    \ctex_if_rescanable:NnTF #1 {#3}
      {
        \use:e
          {
            \@@_patch_replace:nnnTF {#2}
              { \tl_to_str:n {#4} }
              { \tl_to_str:n {#5} }
          }
          {
            \@@_patch_rebuild:Nn #1 {#3}
            \@@_patch_true:w
          }
          { \@@_patch_false:w }
      }
      { \@@_patch_false:w }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_patch_replace:nnnTF}
% 替换前先检查原文本是否存在。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_patch_replace:nnnTF #1#2#3#4
  {
    \tl_if_in:NnTF \l_@@_replacement_str {#2}
      { \use:c { tl_replace_ #1 :Nnn } \l_@@_replacement_str {#2} {#3} #4 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_hookto_cmd:Nnnnw}
% 在宏的前/后附加钩子。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_hookto_cmd:Nnnnw #1#2#3#4
  {
    \group_end:
    \ctex_get_macro_meaning:NTF #1
      {
        \str_if_empty:NTF \l_@@_parameter_str
          { \@@_hookto_cmd_parameterless:Nnnnw }
          { \@@_hookto_cmd_parameter:Nnnnw }
          #1 {#2} {#3} {#4}
      }
      { \@@_patch_false:w }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_hookto_cmd_parameterless:Nnnnw}
% 如果宏没有参数，可以直接进行附加操作。注意保持宏的前缀。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_hookto_cmd_parameterless:Nnnnw #1#2#3#4
  {
    \str_if_empty:NF \l_@@_prefix_str
      { \tl_rescan:no {#3} { \l_@@_prefix_str } }
    \tex_edef:D #1
      {
        \use:c { @@_ #2 _hook_aux:nn }
          { \exp_not:o {#1} }
          { \exp_not:n {#4} }
      }
    \@@_patch_true:w
  }
\cs_generate_variant:Nn \tl_rescan:nn { no }
\cs_new:Npn \@@_left_hook_aux:nn #1#2 { #2#1 }
\cs_new_eq:NN \@@_right_hook_aux:nn \use:nn
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_hookto_cmd_parameter:Nnnnw}
% 如果宏有参数，需要在字符串中进行附加，然后再重建。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_hookto_cmd_parameter:Nnnnw #1#2#3#4
  {
    \@@_patch_rebuild:Nn \@@_rebuild_cmd:w {#3}
    \cs_if_eq:NNTF #1 \@@_rebuild_cmd:w
      {
        \use:c { str_put_ #2 :Nn } \l_@@_replacement_str {#4}
        \@@_patch_rebuild:Nn #1 {#3}
        \@@_patch_true:w
      }
      { \@@_patch_false:w }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%&lt;/ctexpatch&gt;
%    \end{macrocode}
%
% \end{implementation}
%
% \Finale
%
\endinput
</pre></body></html>