% \iffalse meta-comment
%
% File: ctex-auxpkg.dtx
% -----------------------------------------------------------------------
%   Copyright (C) 2003--2026
%   CTEX.ORG and any individual authors listed elsewhere in this file.
% -----------------------------------------------------------------------
%   This work may be distributed and/or modified under the conditions   *
%   of the LaTeX Project Public License (LPPL), either version 1.3c of  *
%   this license or (at your option) any later version.                 *
%   The latest version of this license is in                            *
%                                                                       *
%       http://www.latex-project.org/lppl.txt                           *
%                                                                       *
%   and version 1.3c or later is part of all distributions of LaTeX     *
%   version 2008 or later.                                              *
%                                                                       *
%   This work has the LPPL maintenance status `maintained'.             *
% -----------------------------------------------------------------------
%   This work consists of the files ctex.dtx,                           *
%                                   ctex-kernel.dtx,                    *
%                                   ctex-engine.dtx,                    *
%                                   ctex-scheme.dtx,                    *
%                                   ctex-auxpkg.dtx,                    *
%                                   ctex-fontset.dtx,                   *
%                                   ctexpunct.spa,                      *
%                                   ctxdoc.cls,                         *
%                                   ctxdocstrip.tex,                    *
%                                   ctex-zhconv.lua,                    *
%                                   ctex-zhconv-index.lua,              *
%                                   ctex-zhconv-make.lua,               *
%                 the derived files ctex.ins,                           *
%                                   ctex.sty,                           *
%                                   ctexsize.sty,                       *
%                                   ctexheading.sty,                    *
%                                   ctexart.cls,                        *
%                                   ctexbook.cls,                       *
%                                   ctexrep.cls,                        *
%                                   ctexbeamer.cls,                     *
%                                   ctexcap.sty,                        *
%                                   ctexhook.sty,                       *
%                                   ctexpatch.sty,                      *
%                                   ctex-c5size.clo,                    *
%                                   ctex-cs4size.clo,                   *
%                                   ctex-heading-article.def,           *
%                                   ctex-heading-book.def,              *
%                                   ctex-heading-report.def,            *
%                                   ctex-heading-beamer.def,            *
%                                   ctexbackend.cfg,                    *
%                                   ctex-engine-pdftex.def,             *
%                                   ctex-engine-xetex.def,              *
%                                   ctex-engine-luatex.def,             *
%                                   ctex-engine-aptex.def,              *
%                                   ctex-engine-uptex.def,              *
%                                   ctex-name-utf8.cfg,                 *
%                                   ctex-name-gbk.cfg,                  *
%                                   ctex.cfg,                           *
%                                   ctexopts.cfg,                       *
%                                   ctex-scheme-plain.def,              *
%                                   ctex-scheme-plain-article.def,      *
%                                   ctex-scheme-plain-book.def,         *
%                                   ctex-scheme-plain-report.def,       *
%                                   ctex-scheme-plain-beamer.def,       *
%                                   ctex-scheme-chinese.def,            *
%                                   ctex-scheme-chinese-article.def,    *
%                                   ctex-scheme-chinese-book.def,       *
%                                   ctex-scheme-chinese-report.def,     *
%                                   ctex-scheme-chinese-beamer.def,     *
%                                   ctex-fontset-adobe.def,             *
%                                   ctex-fontset-fandol.def,            *
%                                   ctex-fontset-founder.def,           *
%                                   ctex-fontset-hanyi.def,             *
%                                   ctex-fontset-mac.def,               *
%                                   ctex-fontset-macnew.def,            *
%                                   ctex-fontset-macold.def,            *
%                                   ctex-fontset-ubuntu.def,            *
%                                   ctex-fontset-windows.def,           *
%                                   c19rm.fd,                           *
%                                   c19sf.fd,                           *
%                                   c19tt.fd,                           *
%                                   c70rm.fd,                           *
%                                   c70sf.fd,                           *
%                                   c70tt.fd,                           *
%                                   jy2zhrm.fd,                         *
%                                   jy2zhsf.fd,                         *
%                                   jy2zhtt.fd,                         *
%                                   jt2zhrm.fd,                         *
%                                   jt2zhsf.fd,                         *
%                                   jt2zhtt.fd,                         *
%                                   ctexspa.def,                        *
%                     translator-theorem-dictionary-ChineseUTF8.dict,   *
%                     translator-theorem-dictionary-ChineseGBK.dict,    *
%                                   ctex-spa-make.tex,                  *
%                                   ctex-spa-macro.tex,                 *
%                                   ctex-zhmap-adobe.tex,               *
%                                   ctex-zhmap-fandol.tex,              *
%                                   ctex-zhmap-founder.tex,             *
%                                   ctex-zhmap-hanyi.tex,               *
%                                   ctex-zhmap-mac.tex,                 *
%                                   ctex-zhmap-ubuntu.tex,              *
%                                   ctex-zhmap-windows.tex,             *
%           the documentation files ctex.pdf,                           *
%                               and README.md.                          *
% -----------------------------------------------------------------------
%                                                                       *
%   Any modification of this file should ensure that the copyright and  *
%   license information is placed in the derived files.                 *
%                                                                       *
% -----------------------------------------------------------------------
%
%<*!driver>
%<!dict>\NeedsTeXFormat{LaTeX2e}[2026/06/01]
%<!dict>\RequirePackage{expl3}
%<+!driver>\GetIdInfo $Id: ctex-auxpkg.dtx 2.6.3 2026-07-08 18:13:24 +0800 8c6212ee Mingyu Hsia <myhsia@outlook.com>$
%<ctexcap>  {Chinese adapter in LaTeX (CTEX)}
%<ctexcap>\ProvidesExplPackage{ctexcap}
%<ctexhook>  {Document and package hooks (CTEX)}
%<ctexhook>\ProvidesExplPackage{ctexhook}
%<ctexpatch>  {Patching commands (CTEX)}
%<ctexpatch>\ProvidesExplPackage{ctexpatch}
%<dict&theorem>  {Chinese translation for theorem name (CTEX)}
%<dict&theorem>\ProvidesDictionary{translator-theorem-dictionary}
%<!dict>  {\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
%<dict&theorem&GBK>  {ChineseGBK}%
%<dict&theorem&UTF8>  {ChineseUTF8}%
%<dict&theorem>  [\ExplFileDate\space v\ExplFileVersion\space \ExplFileDescription]
%</!driver>
%
% \fi
%
% \begin{implementation}
%
% \paragraph*{\fbox{\file{\jobname-auxpkg.dtx}}}
%
%    \begin{macrocode}
%<@@=ctex>
%    \end{macrocode}
%
% \subsection{\pkg{translator} 宏包的中文字典}
%
%    \begin{macrocode}
%<*dict>
%    \end{macrocode}
%
% \changes{v2.4}{2016/02/19}{提供 \pkg{translator} 宏包的中文定理名称翻译。}
%
% 包括 \pkg{ChineseGBK} 和 \pkg{ChineseUTF8} 两种形式，目前只翻译 \pkg{beamer}
% 宏包需要的定理环境名称。
%
%    \begin{macrocode}
%<*theorem>
\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}{定理}
%</theorem>
%    \end{macrocode}
%
%    \begin{macrocode}
%</dict>
%    \end{macrocode}
%
% \subsection{\pkg{ctexcap} 宏包}
%
%    \begin{macrocode}
%<*ctexcap>
%    \end{macrocode}
%
% \pkg{ctexcap} 是过时宏包。
%    \begin{macrocode}
\clist_new:N \l_@@_ctexcap_options_clist
\clist_set:Ne \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:nne { 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}
%</ctexcap>
%    \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}
%<*ctexhook>
%    \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:nnee }
      { \@@_disable_package_aux:nnnn }
      { ctexhook } { disable-package } {#1} { \@currname }
  }
\cs_new_protected:Npn \@@_disable_package_aux:nnnn #1#2#3#4
  {
    \cs_if_exist:NTF \disable@package@load
      {
        \exp_args:Nne \disable@package@load {#3}
          { \msg_warning:nnnn {#1} {#2} {#3} {#4} }
      }
      { \tl_const:cn { ver@ #3 . \@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:nne { 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}
%</ctexhook>
%    \end{macrocode}
%
% \subsection{\pkg{ctexpatch} 宏包}
%
% \changes{v2.2}{2015/06/23}{新增子宏包 \pkg{ctexpatch} 实现给宏打补丁功能。}
%
%    \begin{macrocode}
%<*ctexpatch>
%    \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:nne { 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:NNe #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 { NNe }
%    \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 -> \q_mark \q_stop
        }
      \cs_new_protected:Npn \@@_get_macro_meaning:w
          ##1 #1 ##2 -> ##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}
%</ctexpatch>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}
%
% \end{implementation}
