% \iffalse meta-comment
% !TEX program  = XeLaTeX
%<*internal>
\iffalse
%</internal>
%<*readme>

xeCJK is a package written for XeLaTeX which allows users to typeset
CJK scripts easily.


 - different default fonts for CJK and other characters;
 - spaces automatically ignored between CJK characters;
 - special effects on full-width CJK punctuation; and
 - automatic adjustment of the space between CJK and other characters.


This package is licensed in LPPL.

This package consists of the file  xeCJK.dtx,
                                   full-stop.map,
                                   fullwidth-stop.map,
                                   han-simp.map,
                                   han-trad.map,
             and the derived files xeCJK.pdf,
                                   xeCJK.sty,
                                   xeCJK.cfg,
                                   xeCJK.ins,
                                   xeCJKfntef.sty,
                                   xeCJK-listings.sty,
                                   xunicode-addon.sty,
                                   xunicode-extra.def,
                                   xeCJK-example-autofake.tex,
                                   xeCJK-example-fallback.tex,
                                   xeCJK-example-subCJKblock.tex,
                                   xeCJK-example-CJKecglue.tex,
                                   xeCJK-example-checksingle.tex,
                                   xeCJK-example-CJKfntef.tex,
                                   xeCJK-example-punctstyle.tex,
                                   xeCJK-example-verbatim.tex,
                                   xeCJK-example-IVS.tex,
                                   xeCJK-example-listings.tex,
                                   xunicode-symbols.tex,
                                   xunicode-commands.tex,
                                   xunicode-combine-marks.tex,
                                   xunicode-symbols.pdf,
                                   full-stop.tec,
                                   fullwidth-stop.tec,
                                   han-simp.tec,
                                   han-trad.tec, and
                                   README.txt (this file).

If you are interested in the process of development you may observe

    http://code.google.com/p/ctex-kit/updates/list

    Author:
            Wenchang Sun    <sunwch@nankai.edu.cn>
    Current Maintainers:
            Leo Liu         <leoliu.pku@gmail.com>
            Qing Lee        <sobenlee@gmail.com>


Installation
------------
The package is supplied in dtx format and as a pre-extracted zip file,
xecjk.tds.zip. The later is most convenient for most users: simply
unzip this in your local texmf directory and run texhash to update the
database of file locations. If you want to unpack the dtx yourself,
running "xetex xeCJK.dtx" will extract the package whereas
"xelatex xeCJK.dtx" will typeset the documentation.

The package requires LaTeX3 support as provided in the l3kernel and
l3packages bundles and the fontspec package. All of these are available
on CTAN as ready-to-install zip files. Suitable versions are available
in the latest version of MiKTeX and TeX Live (updating the relevant
packages online may be necessary).

To compile the documentation without error, you will need some specific
CJK scripts fonts (TrueType or OpenType).
%</readme>
%<*internal>
\fi
\begingroup
  \edef\tempa{\fmtname}
  \edef\tempb{plain}
\expandafter\endgroup
\ifx\tempa\tempb
\csname fi\endcsname
%</internal>
%<*install>

\input l3docstrip.tex
\keepsilent
\askforoverwritefalse
\preamble

$Id: xeCJK.dtx 750 2014-12-26 08:13:35Z sobenlee@gmail.com $
$URL: https://ctex-kit.googlecode.com/svn/trunk/xeCJK/xeCJK.dtx $
-----------------------------------------------------------------
   Author:
            Wenchang Sun    <sunwch@nankai.edu.cn>
   Current Maintainers:
            Leo Liu         <leoliu.pku@gmail.com>
            Qing Lee        <sobenlee@gmail.com>

   Copyright (C) 2007--2014 Wenchang Sun
             (C) 2009--2014 Leo Liu
             (C) 2012--2014 Qing Lee

   This file may be distributed and/or modified under the
   conditions of the LaTeX Project Public License, either version 1.3
   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.3 or later is part of all distributions of LaTeX
   version 2005/12/01 or later.

   This work has the LPPL maintenance status "maintained".
   The Current Maintainer of this work are Leo Liu and Qing Lee.
-----------------------------------------------------------------

\endpreamble
\postamble

   This package consists of the file  xeCJK.dtx,
                                      full-stop.map,
                                      fullwidth-stop.map,
                                      han-simp.map,
                                      han-trad.map,
                and the derived files xeCJK.pdf,
                                      xeCJK.sty,
                                      xeCJK.cfg,
                                      xeCJK.ins,
                                      xeCJKfntef.sty,
                                      xeCJK-listings.sty,
                                      xunicode-addon.sty,
                                      xunicode-extra.def,
                                      xeCJK-example-autofake.tex,
                                      xeCJK-example-fallback.tex,
                                      xeCJK-example-subCJKblock.tex,
                                      xeCJK-example-CJKecglue.tex,
                                      xeCJK-example-checksingle.tex,
                                      xeCJK-example-CJKfntef.tex,
                                      xeCJK-example-punctstyle.tex,
                                      xeCJK-example-verbatim.tex,
                                      xeCJK-example-IVS.tex,
                                      xeCJK-example-listings.tex,
                                      xunicode-symbols.tex,
                                      xunicode-commands.tex,
                                      xunicode-combine-marks.tex,
                                      xunicode-symbols.pdf,
                                      full-stop.tec,
                                      fullwidth-stop.tec,
                                      han-simp.tec,
                                      han-trad.tec, and
                                      README.txt.
\endpostamble
\declarepreamble\emptypreamble
\endpreamble
\declarepostamble\emptypostamble
\endpostamble

\generate{
  \usedir{source/xelatex/xecjk}
  \file{xeCJK.ins}{\from{\jobname.dtx}{install}}
  \usedir{tex/xelatex/xecjk}
  \file{xeCJK.sty}{\from{\jobname.dtx}{package}}
  \file{xeCJKfntef.sty}{\from{\jobname.dtx}{fntef}}
  \file{xeCJK-listings.sty}{\from{\jobname.dtx}{listings}}
  \file{xunicode-addon.sty}{\from{\jobname.dtx}{xunicode}}
  \file{xunicode-extra.def}{\from{\jobname.dtx}{xunextra}}
  \usepreamble\emptypreamble
  \usepostamble\emptypostamble
  \usedir{tex/xelatex/xecjk/config}
  \file{xeCJK.cfg}{\from{\jobname.dtx}{config}}
  \usedir{doc/xelatex/xecjk/example}
  \file{xeCJK-example-autofake.tex}{\from{\jobname.dtx}{ex-autofake}}
  \file{xeCJK-example-fallback.tex}{\from{\jobname.dtx}{ex-fallback}}
  \file{xeCJK-example-subCJKblock.tex}{\from{\jobname.dtx}{ex-block}}
  \file{xeCJK-example-CJKecglue.tex}{\from{\jobname.dtx}{ex-ecglue}}
  \file{xeCJK-example-checksingle.tex}{\from{\jobname.dtx}{ex-single}}
  \file{xeCJK-example-CJKfntef.tex}{\from{\jobname.dtx}{ex-fntef}}
  \file{xeCJK-example-punctstyle.tex}{\from{\jobname.dtx}{ex-punctstyle}}
  \file{xeCJK-example-verbatim.tex}{\from{\jobname.dtx}{ex-verb}}
  \file{xeCJK-example-IVS.tex}{\from{\jobname.dtx}{ex-IVS}}
  \file{xeCJK-example-listings.tex}{\from{\jobname.dtx}{ex-listings}}
  \file{xunicode-symbols.tex}{\from{\jobname.dtx}{xunicode-symbols}}
  \nopreamble\nopostamble
  \usedir{doc/xelatex/xecjk}
  \file{README.txt}{\from{\jobname.dtx}{readme}}
}

\endbatchfile
%</install>
%<*internal>
\fi
%</internal>
%<*driver|package|config|fntef|listings|xunicode|xunextra>
%<*!config&!xunextra>
\NeedsTeXFormat{LaTeX2e}
\RequirePackage{expl3}
%</!config&!xunextra>
\GetIdInfo$Id: xeCJK.dtx 750 2014-12-26 08:13:35Z sobenlee@gmail.com $
%<*driver|package>
  {Typesetting CJK scripts with XeLaTeX}
%</driver|package>
%<config>  {Configuration file for xeCJK package}
%<fntef>  {xeCJK font effect}
%<listings>  {xeCJK patch file for listings}
%<xunicode>  {addon file for xunicode}
%<xunextra>  {extra definition for xunicode}
%<*driver|config|xunextra>
\ProvidesExplFile
%</driver|config|xunextra>
%<*driver>
  {\ExplFileName.\ExplFileExtension}
%</driver>
%<config>  {\ExplFileName.cfg}
%<xunextra>  {xunicode-extra.def}
%<package|fntef|listings|xunicode>\ProvidesExplPackage
%<package>  {\ExplFileName}
%<fntef>  {xeCJKfntef}
%<listings>  {xeCJK-listings}
%<xunicode>  {xunicode-addon}
  {\ExplFileDate}{3.3.0}{\ExplFileDescription}
%<xunextra>\ExplSyntaxOff
%<*driver>
\let\xeCJKrevnum\ExplFileVersion
\ExplSyntaxOff
%</driver>
%</driver|package|config|fntef|listings|xunicode|xunextra>
%
%<*driver>
\expandafter\let\csname ver@thumbpdf.sty\endcsname\fmtversion
\documentclass[numbered,a4paper,full]{l3doc}
\hypersetup{pdfstartview=FitH}
\usepackage{xeCJK}
\usepackage{xeCJKfntef}
\usepackage{geometry}
\usepackage[toc]{multitoc}
\usepackage{indentfirst}
\usepackage{unicode-math}
\usepackage{fvrb-ex}
\fvset{formatcom=\xeCJKVerbAddon}
\linespread{1.1}
\setlist{noitemsep,topsep=1ex}
\newlist{optiondesc}{description}{3}
\setlist[optiondesc]{font=\mdseries\ttfamily,align=right,labelsep=.5em,leftmargin=4.5em}
\def\PSKeyVal#1#2{\item[#1]\makebox[4em][l]{\meta{#2}}\ignorespaces}
\setmainfont{TeX Gyre Pagella}
\setsansfont{CMU Sans Serif}
\setmonofont[
  UprightFont=* Light, BoldFont=* Bold,
  SlantedFont=* Light Oblique]{CMU Typewriter Text}
\setCJKmainfont[BoldFont=Adobe Heiti Std,ItalicFont=Adobe Kaiti Std]{Adobe Song Std}
\setmathfont{texgyrepagella-math.otf}
\setCJKmonofont{Adobe Kaiti Std}
\xeCJKDeclareSubCJKBlock{HKMD}  { "FF65 }
\xeCJKDeclareSubCJKBlock{Ext-B} { "20000 -> "2A6DF }
\xeCJKDeclareSubCJKBlock{Hangul}{ "1100 -> "11FF, "3130 -> "318F, "A960 -> "A97F, "AC00 -> "D7AF }
\setCJKmainfont[HKMD]{Microsoft YaHei}
\setCJKmainfont[Ext-B]{SimSun-ExtB}
\setCJKmainfont[Hangul, Script=Hangul]{Malgun Gothic}
\xeCJKsetup{PunctStyle=kaiming,KaiMingPunct+={：；}}
\def\MacroFont{\small\linespread{1}\normalfont\ttfamily}
\def\XeTeX{\hologo{XeTeX}}
\def\XeLaTeX{\hologo{XeLaTeX}}
\def\LaTeX{\hologo{LaTeX}}
\def\LaTeXe{\hologo{LaTeX2e}}
\parindent=2em
\AtBeginDocument{\DeleteShortVerb{\"}\MakeShortVerb{\|}}
\def\contentsname{目录}
\DeclareUrlCommand\email{\def\UrlLeft##1\UrlRight{\href{mailto:##1}{##1}}}
\def\ctexkit{\href{http://code.google.com/p/ctex-kit/}{\texttt{ctex-kit}}}
\def\ctexkitrev#1{%
  \href{http://code.google.com/p/ctex-kit/source/detail?r=#1}
       {\texttt{ctex-kit} rev#1}}
\DeclareDocumentCommand\package{om}{%
  \begingroup\edef\x{\endgroup\lowercase{%
    \noexpand\href{http://www.ctan.org/pkg/\IfNoValueTF{#1}{#2}{#1}}}}%
    \x{\pkg{#2}}}
\makeatletter
\ExplSyntaxOn
\NewDocumentCommand \PrintPunctList { O{7} m m }
  {
    \par
    \begingroup
    \CJKfontspec{Microsoft~YaHei}
    \tl_clear:N \l_tmpa_tl
    \int_zero:N \l_tmpa_int
    \tl_set:Nx \l_tmpb_tl { \tl_to_str:n { c__xeCJK_#2_chars_clist } }
    \int_set:Nn \l_tmpb_int { \clist_count:c { \l_tmpb_tl } }
    \clist_map_inline:cn { \l_tmpb_tl }
      {
        \int_incr:N \l_tmpa_int
        \tl_put_right:Nx \l_tmpa_tl
          {
            \use_none:n ##1 & \tex_char:D ##1 \scan_stop:
            \int_compare:nNnF \l_tmpa_int = \l_tmpb_int
              {
                \int_compare:nNnTF { \int_mod:nn \l_tmpa_int {#1} } = \c_zero
                    { \exp_not:N \\ \scan_stop: } { & }
              }
          }
      }
    \noindent\hfill\linespread{1}\selectfont
    \begin{tabular}{|*{#1}{>{\footnotesize\ttfamily U+}c|c|}}
      \tl_use:N \l_tmpa_tl
    \end{tabular}\hfill\null
    \endgroup
    \par
  }
\cs_set_protected:Npn \__codedoc_special_index_aux:nnnnn #1#2#3#4#5
  {
    \__codedoc_special_index_set:Nn \l__codedoc_index_escaped_macro_tl {#2}
    \str_if_eq:onTF { \@currenvir } { macrocode }
      { \codeline@wrindex }
      {
        \HD@target
        \index
      }
      {
        \tl_if_empty:nF { #3 #4 }
          { #3 \actualchar #4 \levelchar }
        #1
        \actualchar
        {
          \token_to_str:N \verbatim@font \c_space_tl
          \l__codedoc_index_escaped_macro_tl
        }
        \encapchar
        hdclindex{\the\c@HD@hypercount}{#5}
      }
  }
\DeclareDocumentCommand \cs { O{} m }
  { \__codedoc_cmd_aux:no {#1} { \c__codedoc_backslash_tl #2 } }
\DeclareDocumentCommand \tn { O{} m }
  {
    \__codedoc_cmd_aux:no
      { index = TeX , replace = false , #1 }
      { \c__codedoc_backslash_tl #2 }
  }
\DeclareDocumentCommand \meta { +m }
  { \__codedoc_meta_aux:n {#1} }
\DeclareExpandableDocumentCommand \bookmarkcstn { O{} m }
  { \tl_to_str:n {#2} }
\cs_new:Npn \bookmarkmeta #1 { < \tl_to_str:n {#1} > }
\cs_generate_variant:Nn \__codedoc_cmd_aux:nn { no }
\AtBeginEnvironment { syntax }
  {
    \char_set_active_eq:NN \| \orbar
    \char_set_active_eq:NN \( \defaultvalaux
  }
\ExplSyntaxOff
\pdfstringdefDisableCommands{%
  \let\cs\bookmarkcstn
  \let\tn\bookmarkcstn
  \let\meta\bookmarkmeta}
\geometry{includemp,hmargin={0mm,15mm},vmargin=15mm,footskip=7mm}
\appto\meta@font@select{\xeCJKsetup{PunctStyle=plain,CJKecglue}}
\preto\IndexParms{\linespread{1}}
\appto\GlossaryParms{%
  \def\@idxitem{\par\hangindent 2em}%
  \def\subitem{\@idxitem\hspace*{1em}}%
  \def\subsubitem{\@idxitem\hspace*{2em}}}
\patchcmd\changes@{\space}{\lbrack}{}{}
\patchcmd\@wrglossary{hdpindex}{hdclindex{\the\c@HD@hypercount}}{}{}
\def\orbar{\textup{\textbar}}
\def\defaultval#1{\textbf{\textup{#1}}}
\def\defaultvalaux#1){\defaultval{#1}}
\def\TF{true\orbar false}
\def\TTF{\defaultval{true}\orbar false}
\def\TFF{true\orbar\defaultval{false}}
\@addtoreset{CodelineNo}{section}
\def\gobblelineno{%
  \addtocounter{CodelineNo}{\m@ne}\let\theCodelineNo\relax}
\def\tokslink#1{\hyperlink{#1}{\ding{51}}}
\makeatother
\def\indexname{代码索引}
\def\glossaryname{版本历史}
\GlossaryPrologue{%
  \addtocounter{secnumdepth}{-10}%
  \section{\glossaryname}}
\IndexPrologue{%
  \section{\indexname}%
  斜体的数字表示对应项说明所在的页码，下划线的数字表示定义所在的代码行号，而直立体的
  数字表示对应项使用时所在的行号。}
\begin{document}
  \DocInput{\jobname.dtx}
  \newgeometry{margin=15mm,footskip=7mm}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \changes{v3.1.0}{2012/11/13}{放弃对 \tn{outer} 宏的特殊处理。}
% \changes{v3.1.1}{2012/12/07}{不再依赖 \pkg{xpatch} 宏包。}
% \changes{v3.2.2}{2013/06/01}{修正某些重音不能正确显示的问题。}
% \changes{v3.2.3}{2013/06/07}{提供四个 TECkit 映射文件用于句号转换和简繁互换。}
% \changes{v3.2.4}{2013/07/02}{遵循 \hologo{LaTeX3} 变量需要预先声明的原则。}
% \changes{v3.2.6}{2013/07/29}{\texttt{case} 类函数的用法与 \hologo{LaTeX3} 同步。}
%
% \CheckSum{9717}
% \GetFileInfo{\jobname.dtx}
%
% \title{\bfseries\pkg{xeCJK} 宏包}
% \author{\href{http://www.ctex.org}{ctex.org}}
% \date{\filedate\qquad\fileversion\thanks{\ctexkitrev{\xeCJKrevnum}.}}
% \maketitle
%
% \tableofcontents
% \vspace{\baselineskip}
%
% \begin{documentation}
%
% \section{简介}
%
% \pkg{xeCJK} 是一个 \XeLaTeX 宏包，用于排版中日韩（CJK）文字。主要功能：
% \begin{enumerate}[labelindent=\parindent,leftmargin=*]
% \item 分别设置 CJK 和英文字体；
% \item 自动忽略 CJK 文字间的空格而保留其它空格，允许在非标点汉字和英文
% 字母 (a -- z, A -- Z) 间断行；
% \item 提供多种标点处理方式： 全角式、半角式、开明式、行末半角式和 CCT 式；
% \item 自动调整中英文间空白。
% \end{enumerate}
%
% \pkg{xeCJK} 使用了 \XeTeX 的一些最新特性，需要 \XeTeX{} |0.9995.0 [2009/06/29]| 以
% 后的版本。\pkg{xeCJK} 依赖 \hologo{LaTeX3} 项目的宏包套件
% \package{l3kernel} 和 \package{l3packages} 。
% \pkg{xeCJK} 还需要通过 \package{fontspec} 宏包来调用系统字体。
% \pkg{xeCJK} 会自动根据需要载入这些宏包。
%
% \pkg{xeCJK} 的原始作者是孙文昌，2009 年 5 月起宏包被收入 \ctexkit\ 项目进行
% 维护，目前主要维护者是刘海洋\footnote{\email{leoliu.pku@gmail.com}} 和
% 李清\footnote{\email{sobenlee@gmail.com}}。
%
% \section{基本用法}
%
% 与其他 \LaTeX{} 宏包一样，引入 \pkg{xeCJK} 宏包只要在导言区使用
% \begin{verbatim}
%     \usepackage{xeCJK}
% \end{verbatim}
% 在引入 \pkg{xeCJK} 宏包之后，只要设置 CJK 文字的字体，就可以在文档中使用中日
% 韩文字了。
%
% 可以在各种文档类中使用 \pkg{xeCJK} 宏包，最简单的示例是：
% \begin{verbatim}
% \documentclass{article}
% \usepackage{xeCJK}
% \setCJKmainfont{SimSun}
%
% \begin{document}
% 中文 \LaTeX 示例。
% \end{document}
% \end{verbatim}
% 上述示例设置了中文字体 SimSun（宋体）。运行此示例要求系统安装了设置的字体，
% 源文件用 UTF-8 编码保存，使用 \XeLaTeX{} 编译。
%
% \pkg{xeCJK} 只提供了字体和标点控制等基本 CJK 语言支持。对于中文文档，可以使
% 用更为高层的 \package{ctex} 宏包或文档类，它将自动调用 \pkg{xeCJK} 并设置好中文
% 字体，同时提供了进一步的本地化支持。详细内容参看 \package{ctex} 宏包套件的说明。
%
% \pkg{xeCJK} 提供了大量选项，可以在宏包调用时作为宏包选项或用 \tn{xeCJKsetup}
% 命令进行设置，详见 \ref{subsec:opts}~节。除了 \tn{setCJKmainfont} 命令，
% \pkg{xeCJK} 还提供了许多其他命令设置和选择中文字体，详见
% \ref{subsec:fontset}~节。其他更详细的功能也都将在下面详细说明。在本文档所在的
% 文件夹的 |example| 目录下面也有一些例子可以参考。
%
% \section{用户手册}
%
% \subsection{宏包选项}
% \label{subsec:opts}
%
% \pkg{xeCJK} 以 \meta{key}|=|\meta{var} 的形式提供宏包选项，你可以在调用宏包
% 的时候直接设置这些选项，也可以在调用宏包之后使用 \tn{xeCJKsetup} 来设置这些选
% 项。\pkg{xeCJK} 内部调用 \pkg{fontspec} 宏包，可以在调用 \pkg{xeCJK} 的时候，
% 使用它的宏包选项。\pkg{xeCJK} 会将 \pkg{fontspec} 的选项传递给它。
%
% \begin{function}{\xeCJKsetup}
%   \begin{syntax}
%     \tn{xeCJKsetup} \{\meta{key_1}=\meta{val_1}, \meta{key_2}=\meta{val_2}, ...\}
%   \end{syntax}
%   其中 \meta{key_1}, \meta{key_2} 是设置选项，而 \meta{val_1}, \meta{val_2} 则是对应选项的
%   设置内容。多个选项可以在一个语句中完成设置。例如
%   \begin{verbatim}
%     \usepackage[PunctStyle=kaiming]{xeCJK}
%   \end{verbatim}
%   等价于
%   \begin{verbatim}
%     \usepackage{xeCJK}
%     ......
%     \xeCJKsetup{PunctStyle=kaiming}
%   \end{verbatim}
% \end{function}
%
% 有些选项或命令后面带有 \hypertarget{expstar}{\hyperlink{expstar}{$\star$}} 号，这表示这
% 个选项或命令只能在导言区中使用，而 \hypertarget{rexpstar}{\hyperlink{rexpstar}{\ding{73}}}
% 号则表示这个选项或命令只能在导言区使用，并且只影响随后定义的 CJK 字体。其余不带特殊标记的
% 选项或命令，如果没有特别说明，可以在导言区或正文中使用。%
% 使用粗体来表示 \pkg{xeCJK} 的默认设置。
%
% \begin{function}[EXP,added=2012-11-22]{LocalConfig}
%   \begin{syntax}
%     LocalConfig = \Arg{\TTF|name}
%   \end{syntax}
%   是否使用本地配置文件 \texttt{xeCJK-\meta{name}.cfg}。\meta{name} 可以是不包含
%   空格的任意使文件名合法的字符串。如果设置为 |true|，则使用的是 \texttt{xeCJK.cfg}；
%   设置为 |false| 则不载入配置文件。可以把将要在下文介绍到的对 \pkg{xeCJK} 的一些
%   设置（例如设置常用 CJK 字体、修改字符范围和定义新的标点输出格式等）保存到文件
%   \texttt{xeCJK-\meta{name}.cfg}。然后把这个文件放在本地的 |TDS| 目录下的适当
%   位置。使用 \TeX~Live 的用户，可以新建下列目录，然后再把
%   \texttt{xeCJK-\meta{name}.cfg} 放在里面：
%   \begin{verbatim}
%     texlive/texmf-local/tex/xelatex/xecjk
%   \end{verbatim}
%   最后还需要在命令行下执行 |mktexlsr|，刷新文件名数据库以便 \TeX 系统能够找到它。
% \end{function}
%
% 请注意，\pkg{xeCJK} 宏包中只有上述 |LocalConfig| 选项需要在调用 \pkg{xeCJK} 时
% 设置，而不能通过 \tn{xeCJKsetup} 来设置。
%
% \begin{function}{xeCJKactive}
%   \begin{syntax}
%     xeCJKactive = \meta{\TTF}
%   \end{syntax}
%   打开/关闭对中文的特殊处理。事实上，这个选项会打开/关闭 \XeTeX 的整个字符类机制，依赖
%   这个机制的宏包都会受到影响。
% \end{function}
%
% \begin{function}{CJKspace}
%   \begin{syntax}
%     CJKspace = \meta{\TFF}
%   \end{syntax}
%   缺省状态下，\pkg{xeCJK} 会忽略 CJK 文字之间的空格，使用这一选项来保留它们之间的空格。
% \end{function}
%
% \begin{function}[EXP]{CJKmath}
%   \begin{syntax}
%     CJKmath = \meta{\TFF}
%   \end{syntax}
%   是否支持在数学环境中直接输入 CJK 字符。使用这个选项后，可以直接在数学环境中
%   输出 CJK 字符。\pkg{url} 宏包将一个 URL 放在一个特殊的数学环境中排版，所以如果在
%   \tn{path} 等命令的路径参数中含有汉字，则需要启用这个选项，路径中的汉字才能显示。
% \end{function}
%
% \begin{function}{CJKglue}
%   \begin{syntax}
%     CJKglue = \{\tn{hskip} 0pt plus 0.08\tn{baselineskip}\}
%   \end{syntax}
%   设置 CJK 文字之间插入的 |glue|，上边是 \pkg{xeCJK} 的默认值。一般来说，除非有
%   特殊需要（例如，改变文字间距等），否则不需要设置这个选项，使用默认值即可。如果要设置
%   这个选项，为了行末的对齐，设置的 |glue| 最好有一定的弹性。
% \end{function}
%
% \begin{function}{CJKecglue}
%   \begin{syntax}
%     CJKecglue = \Arg{glue}
%   \end{syntax}
%   设置 CJK 文字与西文、CJK 文字与行内数学公式之间的间距，默认值是一个空格。使用这个
%   选项设置的 |glue| 最好也要用一定的弹性。请注意，这里设置的 |glue| 只影响
%   \pkg{xeCJK} 根据需要自动添加的空白，源文件中直接输入的 CJK 文字与西文之间的空格不
%   受影响（直接输出）。有时候 \pkg{xeCJK} 可能不能正确地调整间距，需要手动加空格。
% \end{function}
%
% \begin{function}{xCJKecglue}
%   \begin{syntax}
%     xCJKecglue = \Arg{\TFF|glue}
%   \end{syntax}
%   缺省状态下，\pkg{xeCJK} 不对源文件中直接输入的 CJK 文字与西文之间的空格进行调整，如
%   果需要调整，请使用这个选项。如果使用这个选项，将使用 |CJKecglue| 替换源文件中直接输
%   入的 CJK 文字与西文之间的空格。
% \end{function}
%
% \begin{function}[updated=2013-06-26]{CheckSingle}
%   \begin{syntax}
%     CheckSingle = \meta{\TFF}
%   \end{syntax}
%   是否避免单个 CJK 文字单独占一个段落的最后一行。需要说明的是，这个选项只有在
%   段末的最后一个字是 CJK 文字或者标点符号，并且倒数第二和第三个字都是文字才能
%   正确处理处理孤字的问题。如果这倒数三个字有作为控制序列的参数的情况，那么一般
%   来说也不能正确处理。
% \end{function}
%
% \begin{function}[added=2012-12-06]{PlainEquation}
%   \begin{syntax}
%     PlainEquation = \meta{\TFF}
%   \end{syntax}
%   如果使用了 |$$...$$| 的形式来输入行间数学公式，就需要启用本选项，以便
%   |CheckSingle| 选项能够正确识别。推荐使用 |\[...\]| 的形式来输入行间数学公式。
% \end{function}
%
% \begin{function}[added=2012-12-04]{NewLineCS,NewLineCS+,NewLineCS-}
%   \begin{syntax}
%     NewLineCS = \{ \tn{par} \tn{[} \}
%   \end{syntax}
%   设置造成断行的控制序列，以便 |CheckSingle| 选项能够正确识别。
%   以上是 \pkg{xeCJK} 的初始设置。
% \end{function}
%
% \begin{function}[added=2012-12-04]{EnvCS,EnvCS+,EnvCS-}
%   \begin{syntax}
%     EnvCS = \{ \tn{begin} \tn{end} \}
%   \end{syntax}
%   设置 \LaTeX 环境开始和结束的控制序列，以便 |CheckSingle| 选项能够正确识别。
%   以上是 \pkg{xeCJK} 的初始设置。
% \end{function}
%
% \begin{function}[updated=2012-12-06]{InlineEnv,InlineEnv+,InlineEnv-}
%   \begin{syntax}
%     InlineEnv = \{\meta{env_1}, \meta{env_2}, \meta{env_3}, ...\}
%   \end{syntax}
%   在使用 |CheckSingle| 选项的时候，\pkg{xeCJK} 会将 CJK 文字后接着的 \LaTeX 环境的
%   开始 |\begin{...}| 和结束 |\end{...}| 视为断行的地方，如果有某些特殊
%   的 \LaTeX 环境没有造成断行，可以使用这个选项来声明它，以便 |CheckSingle| 能正确识别。
% \end{function}
%
% \begin{function}{AutoFallBack}
%   \begin{syntax}
%     AutoFallBack = \meta{\TFF}
%   \end{syntax}
%   当文档中有个别生僻字时，可以使用这个选项，自动使用预先设置好的后备字体来输出这些生僻
%   字。后备字体的设置方法将在 \ref{subsec:fontset} 节中介绍。
% \end{function}
%
% \begin{function}[rEXP]{AutoFakeBold}
%   \begin{syntax}
%     AutoFakeBold = \Arg{\TFF|数字}
%   \end{syntax}
%   全局设定当没有声明对应的粗体时，是否使用\textbf{\CJKfontspec[AutoFakeBold]{Adobe Song Std}伪粗体}；
%   当输入的是数字时，将使用伪粗体，并将使用输入的数字作为伪粗体的默认粗细程度。
% \end{function}
%
% \begin{function}[rEXP]{AutoFakeSlant}
%   \begin{syntax}
%     AutoFakeSlant = \Arg{\TFF|数字}
%   \end{syntax}
%   全局设定当没有声明对应的斜体时，是否使用\textit{\CJKfontspec[AutoFakeSlant]{Adobe Song Std}伪斜体}；
%   当输入的是数字时，将使用伪斜体，并将使用输入的数字作为伪斜体的默认倾斜程度。
% \end{function}
%
% \begin{function}[rEXP]{EmboldenFactor}
%   \begin{syntax}
%     EmboldenFactor = \Arg{数字|(4)}
%   \end{syntax}
%   设置伪粗体的默认粗细程度。
% \end{function}
%
% \begin{function}[rEXP]{SlantFactor}
%   \begin{syntax}
%     SlantFactor = \Arg{数字|(0.167)}
%   \end{syntax}
%   设置伪斜体的粗细程度，范围是 $-0.999 \sim 0.999$。
% \end{function}
%
% \begin{function}[updated=2012-11-10]{PunctStyle}
%   \begin{syntax}
%     PunctStyle = \Arg{(quanjiao)|banjiao|kaiming|hangmobanjiao|CCT|plain|...}
%   \end{syntax}
%   设置标点处理格式。\pkg{xeCJK} 中预先定义好的格式为
%   \begin{description}[font=\mdseries\ttfamily,align=right,labelsep=1em,labelindent=2em,leftmargin=*]
%     \item[quanjiao] 全角式：所有标点占一个汉字宽度，相邻两个标点占 1.5 汉字宽度；
%     \item[banjiao]  半角式：所有标点占半个汉字宽度；
%     \item[kaiming]  开明式：句末点号用全角，其他半角；
%     \item[hangmobanjiao] 行末半角式：所有标点占一个汉字宽度，行首行末对齐；
%     \item[CCT]   CCT 格式：所有标点符号的宽度略小于一个汉字宽度；
%     \item[plain] 原样（不调整标点间距）。
%   \end{description}
%   可以使用 \ref{subsec:punctstyle} 中介绍的 \tn{xeCJKDeclarePunctStyle} 定义新的标点
%   格式。
% \end{function}
%
% \begin{function}[EXP]{KaiMingPunct,KaiMingPunct+,KaiMingPunct-}
%   \begin{syntax}
%     KaiMingPunct = \Arg{( ． 。？ ！)}
%   \end{syntax}
%   设置开明（|kaiming|）标点处理格式时的句末点号，|KaiMingPunct| 后带的 |+| 与 |-|
%   分别表示从已有的开明句末点号中增加或减少标点。
% \end{function}
%
% \begin{function}[EXP]{LongPunct,LongPunct+,LongPunct-}
%   \begin{syntax}
%     LongPunct = \Arg{( — ― ─ ‥ … )}
%   \end{syntax}
%   设置长标点，例如破折号“——”与省略号“……”，允许在长标点前后
%   断行，但是禁止在它们之间断行。
% \end{function}
%
% \begin{function}[EXP]{MiddlePunct,MiddlePunct+,MiddlePunct-}
%   \begin{syntax}
%     MiddlePunct = \Arg{( — ― ─ · · ･ )}
%   \end{syntax}
%   设置居中显示的标点，例如间隔号“\textbf{·}”。对于在 CJK 文字之间的居中标点，
%   \pkg{xeCJK} 会根据不同的标点处理格式，调整居中标点与前后文字之间的空白，保证
%   其确实居中。对于行末出现的居中标点，允许在其后面断行，但禁止在它前面断行。
% \end{function}
%
% \begin{function}[EXP]{PunctWidth}
%   \begin{syntax}
%     PunctWidth = \Arg{length}
%   \end{syntax}
%   缺省状态下，\pkg{xeCJK} 会根据所选择的标点处理格式自动计算标点所占的宽度，如果对缺
%   省设置不满意，可以通过这一选项来改变它。为了使得标点所占的宽度能够适应字体大小的变化，
%   这里设置的 |length| 的单位最好用 |em| 等相对距离单位，而不建议使用诸如 |pt| 之类的
%   绝对距离单位。这里的设置可用于除了 |plain| 以外的所有标点处理格式。同时，这里的
%   设置对所有的 CJK 标点都生效，如果只要设置部分标点，请使用 \ref{subsec:punct}~节的
%   \tn{xeCJKsetwidth}。
% \end{function}
%
% \begin{function}[EXP,added=2013-08-22]{PunctBoundWidth}
%   \begin{syntax}
%     PunctBoundWidth = \Arg{length}
%   \end{syntax}
%   与以上选项类似，但设置的是标点符号出现在行首/尾时的宽度。
% \end{function}
%
% \begin{function}{AllowBreakBetweenPuncts}
%   \begin{syntax}
%     AllowBreakBetweenPuncts = \meta{\TFF}
%   \end{syntax}
%   缺省状态下，\pkg{xeCJK} 禁止在相邻 CJK 右标点和 CJK 左标点之间换行，可以使用
%   这一选项改变这一设置。
% \end{function}
%
% \begin{function}[added=2014-05-13]{RubberPunctSkip}
%   \begin{syntax}
%     RubberPunctSkip = \meta{\TTF}
%   \end{syntax}
%   缺省状态下，标点符号前/后的间距有一定的弹性。让本选项设置为 \texttt{false}
%   可以禁用这一特性，从而使得前/后的间距为固定值。
% \end{function}
%
% \begin{function}[added=2012-12-02]{CheckFullRight}
%   \begin{syntax}
%     CheckFullRight = \meta{\TFF}
%   \end{syntax}
%   某些控制序列要求不能在它的前面断行。但是在缺省状态下，单个全角右标点的后面总是
%   可以断行的。因此当这些控制序列出现在全角右标点后面时，可能会出现意料之外的断行。
%   此时可以使用这个选项来避免这个情况。
% \end{function}
%
% \begin{function}[added=2012-12-02]{NoBreakCS,NoBreakCS+,NoBreakCS-}
%   \begin{syntax}
%     NoBreakCS = \{ \tn{footnote} \tn{footnotemark} \tn{nobreak} \}
%   \end{syntax}
%   设置不能在全角右标点后断行的控制序列。以上是 \pkg{xeCJK} 的默认设置。如果这些
%   控制序列在文档中只出现少量几次，也可以不必使用 |CheckFullRight| 选项，而是手工
%   在这些控制序列前面加上 \ref{subsec:others}~节介绍的 \tn{xeCJKnobreak}。
% \end{function}
%
% \begin{function}[updated=2013-11-16]{Verb}
%   \begin{syntax}
%     Verb = \meta{\TF|(env)|env+}
%   \end{syntax}
%   \texttt{true} 表示在 \tn{verb} 命令或 \texttt{verbatim} 环境里不自动调整中英文
%   之间的间距。\texttt{env} 选项在 \texttt{verbatim} 环境里自动计算中西文间距和中文
%   之间的间距，以便于保持代码的对齐；\texttt{env} 选项不调整 \tn{verb} 里的间距，^^A
%   \texttt{env+} 选项还将正文里设置的间距应用到 \tn{verb} 里。^^A
%   这个选项对使用到 \tn{verbatim@font} 命令的情形均有效，更一般的情况可以使用
%   \ref{subsec:others}~节介绍的 \tn{xeCJKVerbAddon}。\texttt{false} 表示不作任何
%   处理。以上选项的值除 \texttt{false} 外，都禁止在汉字之间和汉字与西文之间自动换行。
% \end{function}
%
% \begin{function}[rEXP,added=2014-03-01]{LoadFandol}
%   \begin{syntax}
%     LoadFandol = \meta{\TTF}
%   \end{syntax}
%   当没有在导言区设置 CJK 字体时，是否使用 Fandol 字体。如果启用这个选项，需要
%   安装 \package{Fandol} 字体系列。
% \end{function}
%
% \subsection{字体设置与选择}
% \label{subsec:fontset}
%
% \begin{function}[EXP]{\setCJKmainfont}
%   \begin{syntax}
%     \tn{setCJKmainfont} \oarg{font features} \Arg{font name}
%   \end{syntax}
%   设置正文罗马族的 CJK 字体，影响 \tn{rmfamily} 和 \tn{textrm} 的字体。后面两个
%   参数继承自 \pkg{fontspec} 宏包， \meta{font features} 表示字体属性选项，
%   \meta{font name} 是字体名。字体名可以是字体族名，也可以是字体的文件名，查
%   找字体名见 \ref{subsubsec:fontsearch}~节；可用的字体属性选项参见
%   \pkg{fontspec} 宏包的文档。需要说明的是 \pkg{xeCJK} 修改了 |AutoFakeBold|
%   和 |AutoFakeSlant| 选项，以便配合全局伪粗体和伪斜体的设定。
% \end{function}
%
% \begin{function}{AutoFakeBold,AutoFakeSlant}
%   \begin{syntax}
%     AutoFakeBold  = \Arg{\TF|数字}
%     AutoFakeSlant = \Arg{\TF|数字}
%   \end{syntax}
%   局部设置当前字体族的伪粗和伪斜属性。如果没有在局部给出这些选项，将使用全局设定。
% \end{function}
%
% \begin{function}[added=2013-06-07]{Mapping}
%   \begin{syntax}
%     Mapping = \Arg{fullwidth-stop|full-stop|han-trad|han-simp|...}
%   \end{syntax}
%   \pkg{xeCJK} 提供了以上四个 \href{http://scripts.sil.org/teckit}{TECKit} 映射
%   文件，可以在设置字体的时候通过 \texttt{Mapping} 选项来使用它们。其中
%   \texttt{fullwidth-stop} 用于将正常句号“。”转换成全角实心句号“．”，
%   \texttt{full-stop} 的作用相反。\texttt{han-trad} 用于将简体中文转换成繁体中文，
%   \texttt{han-simp} 的作用相反。需要注意的是，简繁互换都是简单机械的字字对译，
%   不能做到完全准确，使用时要小心。例如简体的“发挥”和“头发”被转换成繁体的
%   “發揮”和“頭發”，显然后者应作“頭髮”。也可以根据实际需要，制作新的映射文件，
%   请参考 TECKit 的文档。
% \end{function}
%
% \begin{function}[EXP]{\setCJKsansfont}
%   \begin{syntax}
%     \tn{setCJKsansfont} \oarg{font features} \Arg{font name}
%   \end{syntax}
%   设置正文无衬线族的 CJK 字体，影响 \tn{sffamily} 和 \tn{textsf} 的字体。
% \end{function}
%
% \begin{function}[EXP]{\setCJKmonofont}
%   \begin{syntax}
%     \tn{setCJKmonofont}  \oarg{font features} \Arg{font name}
%   \end{syntax}
%   设置正文等宽族的 CJK 字体，影响 \tn{ttfamily} 和 \tn{texttt} 的字体。
% \end{function}
%
% \begin{function}[EXP]{\setCJKfamilyfont}
%   \begin{syntax}
%     \tn{setCJKfamilyfont} \Arg{family} \oarg{font features} \Arg{font name}
%   \end{syntax}
%   声明新的 CJK 字体族 \meta{family} 并指定字体。
% \end{function}
%
% \begin{function}[updated=2012-10-27]{\CJKfamily}
%   \begin{syntax}
%     \tn{CJKfamily}  \Arg{family}
%     \tn{CJKfamily} + \Arg{family}
%     \tn{CJKfamily} - \Arg{family}
%   \end{syntax}
%   用于在文档中切换 |CJK| 字体族，\meta{family} 必须预先声明。\tn{CJKfamily} 仅对
%   CJK 字符类有效，\tn{CJKfamily}|+| 对所有字符类均有效，\tn{CJKfamily}|-| 对非 CJK 字
%   符类有效。当 \tn{CJKfamily}|+| 和 \tn{CJKfamily}|-| 的参数为空时，则使用当前的 |CJK| 字体族。
% \end{function}
%
% \begin{function}[EXP]{\newCJKfontfamily}
%   \begin{syntax}
%     \tn{newCJKfontfamily} \oarg{family} \cs{\meta{font-switch}} \oarg{font features} \Arg{font name}
%   \end{syntax}
%   声明新的 CJK 字体族 \meta{family} 并指定字体，并定义 \cs{\meta{font-switch}}，在
%   文档中可以使用它来切换 CJK 字体族。可以不必指定 \meta{family}，这时候 \meta{family}
%   将等于 \meta{font-switch}。事实上，\tn{newCJKfontfamily} 是 \tn{setCJKfamilyfont} 和
%   \tn{CJKfamily} 的合并。例如
%   \begin{verbatim}
%     \newCJKfontfamily[song]\songti{SimSun}
%   \end{verbatim}
%   等价于
%   \begin{verbatim}
%     \setCJKfamilyfont{song}{SimSun}
%     \newcommand*{\songti}{\CJKfamily{song}}
%   \end{verbatim}
% \end{function}
%
% \begin{function}{\CJKfontspec}
%   \begin{syntax}
%     \tn{CJKfontspec} \oarg{font features} \Arg{font name}
%   \end{syntax}
%   在文档中随机定义新的 CJK 字体族，并马上使用它。
% \end{function}
%
% \begin{function}[rEXP]{\defaultCJKfontfeatures}
%   \begin{syntax}
%     \tn{defaultCJKfontfeatures} \Arg{font features}
%   \end{syntax}
%   全局设置 CJK 字体族的默认选项。例如，使用
%   \begin{verbatim}
%     \defaultCJKfontfeatures{Scale=0.962216}
%   \end{verbatim}
%   可以将全部 CJK 字体缩小为 |0.962216|。\pkg{xeCJK} 宏包的初始化设置是
%   \begin{verbatim}
%     \defaultCJKfontfeatures{Script=CJK}
%   \end{verbatim}
% \end{function}
%
% \begin{function}[updated=2013-06-30]{\addCJKfontfeatures}
%   \begin{syntax}
%     \tn{addCJKfontfeatures}   \Arg{font features}
%     \tn{addCJKfontfeatures} * \Arg{font features}
%     \tn{addCJKfontfeatures}   \oarg{block_1, block_2, ...} \Arg{font features}
%     \tn{addCJKfontfeatures} * \oarg{block_1, block_2, ...} \Arg{font features}
%   \end{syntax}
%   临时增加当前使用的 CJK 字体的选项。第一条命令，仅对当前 CJK 主分区字体有效；
%   第二条对主分区和其它分区的字体都有效；第三条仅对可选参数中指定的分区有效；
%   第四条对主分区和可选参数中指定的分区有效。例如，使用
%   \begin{verbatim}
%     \addCJKfontfeatures{Scale=1.1}
%   \end{verbatim}
%   可以将文档中当前使用的 CJK 主分区字体放大为 |1.1|。
% \end{function}
%
% \begin{function}{\CJKrmdefault}
%   保存 \tn{textrm} 和 \tn{rmfamily} 所使用的 CJK 字体族，默认值是 |rm|。
%   类似西文字体的 \tn{rmdefault}。
% \end{function}
%
% \begin{function}{\CJKsfdefault}
%   保存 \tn{textsf} 和 \tn{sffamily} 所使用的 CJK 字体族，默认值是 |sf|。
%   类似西文字体的 \tn{sfdefault}。
% \end{function}
%
% \begin{function}{\CJKttdefault}
%   保存 \tn{texttt} 和 \tn{ttfamily} 所使用的 CJK 字体族，默认值是 |tt|。
%   类似西文字体的 \tn{ttdefault}。
% \end{function}
%
% \begin{function}[updated=2013-01-01]{\CJKfamilydefault}
%   保存 \tn{textnormal} 和 \tn{normalfont} 所使用的 CJK 字体族。类似西文字体的 \tn{familydefault}。
%   初始值是 \tn{CJKrmdefault}。如果没有在导言区中修改它，\pkg{xeCJK} 会在导言区
%   结束的时候根据西文字体的情况自动更新 \tn{CJKfamilydefault}。因此，在导言区里使用
%   \begin{verbatim}
%     \renewcommand\familydefault{\sfdefault}
%   \end{verbatim}
%   就可以将全文的 CJK 和西文默认字体都改为无衬线字体族。
% \end{function}
%
% \begin{function}[EXP]{\setCJKmathfont}
%   \begin{syntax}
%     \tn{setCJKmathfont} \oarg{font features} \Arg{font name}
%   \end{syntax}
%   设置数学公式中的 CJK 字体族。如果使用了 |CJKmath| 选项，但是没有使用
%   \tn{setCJKmathfont} 设置数学公式中的 CJK 字体，那么将使用 \tn{CJKfamilydefault}
%   作为数学公式中的 CJK 字体。
% \end{function}
%
% \begin{function}[EXP]{\setCJKfallbackfamilyfont}
%   \begin{syntax}
%     \tn{setCJKfallbackfamilyfont} \Arg{family} \oarg{font features} \Arg{font name}
%   \end{syntax}
%   设置 CJK 字体族 \meta{family} 的备用字体。例如，使用
%   \begin{verbatim}
%     \setCJKmainfont{SimSun}
%     \setCJKfallbackfamilyfont{\CJKrmdefault}{SimSun-ExtB}
%   \end{verbatim}
%   可以将 |SimSun-ExtB| 作为 |SimSun| 的备用字体。
% \end{function}
%
% \begin{function}{FallBack}
%   \begin{syntax}
%     FallBack = \{\oarg{font features}\Arg{font name}\}
%   \end{syntax}
%   \pkg{xeCJK} 在 \meta{font features} 里增加了 |FallBack| 这个选项。用来在声明主
%   字体的时候，同时设置备用字体。例如，上面的例子等价于：
%   \begin{verbatim}
%     \setCJKmainfont[FallBack=SimSun-ExtB]{SimSun}
%   \end{verbatim}
%   如果 |FallBack| 的值为空，将设置的是备用字体。例如，
%   \begin{verbatim}
%     \setCJKmainfont[FallBack,AutoFakeBold,Scale=.97]{SimSun-ExtB}
%   \end{verbatim}
%   等价于
%   \begin{verbatim}
%     \setCJKfallbackfamilyfont{\CJKrmdefault}[AutoFakeBold,Scale=.97]{SimSun-ExtB}
%   \end{verbatim}
% \end{function}
%
% \begin{function}[EXP,updated=2013-06-30]{\setCJKfallbackfamilyfont}
%   \begin{syntax}
%     \tn{setCJKfallbackfamilyfont} \Arg{family} \oarg{common font features}
%        \  \{
%        \    \{\oarg{font features_1} \Arg{font name_1}\} ,
%        \    \{\oarg{font features_2} \Arg{font name_2}\} ,
%        \     ......
%        \  \}
%   \end{syntax}
%   \tn{setCJKfallbackfamilyfont} 还可以用于设置多层的备用字体。例如，使用
%   \begin{verbatim}
%     \setCJKmainfont[AutoFakeBold,AutoFakeSlant]{KaiTi_GB2312}
%     \setCJKfallbackfamilyfont{\CJKrmdefault}[AutoFakeSlant]
%       { [BoldFont=SimHei]{SimSun} ,
%         [AutoFakeBold]   {SimSun-ExtB} }
%   \end{verbatim}
%   之后，就设置了 |SimSun| 是 |KaiTi_GB2312| 的备用字体，而 |SimSun-ExtB| 是
%   |SimSun| 的备用字体。若当前字体族缺字，并没有备用字体，则尝试使用
%   \tn{CJKfamilydefault} 的备用字体。
% \end{function}
%
% \subsubsection{\XeTeX 的字体名查找}
% \label{subsubsec:fontsearch}
%
% 由于在 \pkg{fontspec} 宏包文档中缺少关于如何查看 \XeTeX{} 可用字体名的说明，
% 这里略作说明。
%
% \XeTeX{} 通常使用 fontconfig 库查找和调用字体，因此，可以用 |fc-list| 命令显
% 示可用的字体。在命令行（Windows 的“命令提示符”，Linux 的 Console）下运行以
% 下命令：
% \begin{verbatim}
%     fc-list > fontlist.txt
% \end{verbatim}
% 可以将系统中所有安装的字体列表存入 \file{fontlist.txt} 文件中（可能很长）。
%
% |fc-list| 命令列出的信息很多，而且在安装字体较多的 Windows 系统上的输出将非
% 常庞大，如其中可能包含：
% \begin{verbatim}
% Times New Roman:style=cursiva,kurzíva,kursiv,Πλάγια,Italic,
%   Kursivoitu,Italique,Dőlt,Corsivo,Cursief,kursywa,Itálico,Курсив,
%   İtalik,Poševno,nghiêng,Etzana
% Times New Roman:style=Negreta cursiva,tučné kurzíva,fed kursiv,
%   Fett Kursiv,Έντονα Πλάγια,Bold Italic,Negrita Cursiva,
%   Lihavoitu Kursivoi,Gras Italique,Félkövér dőlt,Grassetto Corsivo,
%   Vet Cursief,Halvfet Kursiv,Pogrubiona kursywa,Negrito Itálico,
%   Полужирный Курсив,Tučná kurzíva,Fet Kursiv,Kalın İtalik,
%   Krepko poševno,nghiêng đậm,Lodi etzana
% Times New Roman:style=Negreta,tučné,fed,Fett,Έντονα,Bold,Negrita,
%   Lihavoitu,Gras,Félkövér,Grassetto,Vet,Halvfet,Pogrubiona,Negrito,
%   Полужирный,Fet,Kalın,Krepko,đậm,Lodia
% Times New Roman:style=Normal,obyčejné,Standard,Κανονικά,Regular,
%   Normaali,Normál,Normale,Standaard,Normalny,Обычный,Normálne,Navadno,
%   thường,Arrunta
% 宋体,SimSun:style=Regular
% 黑体,SimHei:style=Normal,obyčejné,Standard,Κανονικά,Regular,Normaali,
%   Normál,Normale,Standaard,Normalny,Обычный,Normálne,Navadno,Arrunta
% \end{verbatim}
% 在 \pkg{fontspec} 或 \pkg{xeCJK} 中使用的字体族名是上面列表中冒号前的部分。
% 例如可以使用
% \begin{verbatim}
%     \setmainfont{Times New Roman}
%     \setCJKmainfont{SimSun} % 或者 \setCJKmainfont{宋体}
% \end{verbatim}
% 来设置字体。
%
% 为了方便起见，|fc-list| 命令也可以加上各种选项控制输出格式，例如如果只要列出
% 所有的中文字体的字体族名，可以用命令：
% \begin{verbatim}
%     fc-list -f "%{family}\n" :lang=zh  > zhfont.txt
% \end{verbatim}
% 这样就把字体列表保存在文件 \file{zhfont.txt} 中\footnote{由于汉字编码原因，
% Windows 下总需要把字体列表输出的文件中防止乱码。}。这样列出的字体列表就比较
% 简明易用，如 Windows 下预装的中文字体：
% \begin{verbatim}
% Arial Unicode MS
% FangSong,仿宋
% KaiTi,楷体
% Microsoft YaHei,微软雅黑
% MingLiU,細明體
% NSimSun,新宋体
% PMingLiU,新細明體
% SimHei,黑体
% SimSun,宋体
% \end{verbatim}
% 要列出日文和韩文的字体，可以把 |:lang=zh| 选项中的 |zh| 改成 |ja| 或 |ko|。
%
% \pkg{fontspec} 和 \pkg{xeCJK} 也可以使用字体的文件名访问字体。例如 Windows
% 下的宋体也可以使用命令：
% \begin{verbatim}
%     \setCJKmainfont{simsun.ttc}
% \end{verbatim}
% 来设置。设置字体文件名的相关选项和语法在 \pkg{fontspec} 宏包手册中叙述甚详，
% 这里不再赘述。有个别字体名不规范的中文字体，\pkg{xeCJK} 宏包可能无法正确地通
% 过字体名访问，那么也可以使用这种方式设置。
%
% \subsection{CJK 分区字体设置}
% \label{subsec:block}
%
% 众所周知，CJK 文字数量极其庞大，单一的字体不可能涵盖所有的 CJK 文字。\pkg{xeCJK} 可
% 以在同一 CJK 字体族下，自动使用不同的字体输出 CJK 字符范围内不同区块里的文字。首先要
% 声明 CJK 子分区。
%
% \begin{function}[EXP]{\xeCJKDeclareSubCJKBlock}
%   \begin{syntax}
%     \tn{xeCJKDeclareSubCJKBlock}  \Arg{block} \Arg{block range}
%     \tn{xeCJKDeclareSubCJKBlock} * \Arg{block} \Arg{block range}
%   \end{syntax}
%   其中 \meta{block range} 是逗号列表，可以是 CJK 字符的 |Unicode| 范围，也可以是单个字符
%   的 |Unicode|。例如\strut
% \end{function}
%   \begin{verbatim}
%     { `中 -> `文 , "3400 -> "4DBF , "5000 -> "7000 , `汉 , `字 , "3500 }
%   \end{verbatim}
%   的形式。需要注意的是，这里设置的 \meta{block range} 除非确实需要（例如某些特殊字体使用
%   了 |Unicode| 中的私人使用区的情况），否则不要超出源代码中预设的
%   \hyperlink{CJKcharclass}{CJK 文字范围}。使用
%   \begin{verbatim}
%     \xeCJKDeclareSubCJKBlock{SPUA}{ "E400 -> "E4DA , "E500 -> "E5E8 , "E600 -> "E6CE }
%     \xeCJKDeclareSubCJKBlock{Ext-B}{ "20000 -> "2A6DF }
%   \end{verbatim}
%   就声明了 |SPUA| 和 |Ext-B| 这两个个子分区。同时在 \ref{subsec:fontset} 节介绍的
%   CJK 字体设置命令的 \meta{font features} 里新建了 |SPUA| 和 |Ext-B| 这两个选项。
%   新建的这两个选项的使用方法跟 \ref{subsec:fontset} 介绍的 |FallBack| 类似。可以
%   通过它们来设置字体。
%
%   例如，可以使用
%   \begin{verbatim}
%     \setCJKmainfont[SPUA=SunmanPUA,Ext-B=SimSun-ExtB]{SimSun}
%   \end{verbatim}
%   设置文档的主字体是 |SimSun|，|SPUA| 分区的字体是 |SunmanPUA|，而 |Ext-B| 分区
%   的字体是 |SimSun-ExtB|。
%
%   \tn{xeCJKDeclareSubCJKBlock} 应该在声明所有的 CJK 字体族之前使用。如果有某个 CJK 字
%   体族没有设置 \meta{block} 选项，将使用 \tn{CJKfamilydefault} 的 \meta{block} 选项
%   作为该 CJK 字体族的 \meta{block} 选项。如果希望在使用某 CJK 字体族时，不在 CJK 主
%   分区与 \meta{block} 之间切换字体，可以使用 \meta{block}|=*| 选项。带星号的命令除了
%   设置 CJK 子分区以外，还重置标点符号所属的字符类。
%
% \begin{function}{\xeCJKCancelSubCJKBlock}
%   \begin{syntax}
%     \tn{xeCJKCancelSubCJKBlock}  \Arg{block_1, block_2, ...}
%     \tn{xeCJKCancelSubCJKBlock} \Arg{block_1, block_2, ...}
%   \end{syntax}
%   在文档中取消对 |CJK| 分区的声明。带星号的命令还重置标点符号所属的字符类。
% \end{function}
%
% \begin{function}{\xeCJKRestoreSubCJKBlock}
%   \begin{syntax}
%     \tn{xeCJKRestoreSubCJKBlock}  \Arg{block_1, block_2, ...}
%     \tn{xeCJKRestoreSubCJKBlock} * \Arg{block_1, block_2, ...}
%   \end{syntax}
%   在文档中恢复对 |CJK| 分区的声明。带星号的命令还重置标点符号所属的字符类。
% \end{function}
%
% \subsection{设置 CJK 字符范围}
%
% \begin{function}[EXP]{\xeCJKDeclareCharClass}
%   \begin{syntax}
%     \tn{xeCJKDeclareCharClass}  \Arg{class} \Arg{class range}
%     \tn{xeCJKDeclareCharClass} * \Arg{class} \Arg{class range}
%   \end{syntax}
%   \meta{class range} 的格式和 \ref{subsec:block} 节的 \meta{block range} 相同。
%   \meta{class} 的有效值见源代码（第 \ref{sec:xeCJK-class-set} 节）。\pkg{xeCJK} 已
%   经支持 |Unicode| 中所有 CJK 文字和标点。一般来说，不要轻易改变字符类别。带星号的
%   命令除了设置字符类别以外，为了确保标点处理的正确性，还重置标点符号所属的字符类。
% \end{function}
%
% \begin{function}[EXP]{\xeCJKResetCharClass}
%   用于恢复 \pkg{xeCJK} 对各个字符类别的初始化设置。
% \end{function}
%
% \begin{function}[EXP]{\xeCJKResetPunctClass}
%   用于重置标点符号所属的字符类。
% \end{function}
%
% \begin{function}{\normalspacedchars}
%   \begin{syntax}
%     \tn{normalspacedchars} \Arg{char list}
%   \end{syntax}
%   在 \meta{char list} 中出现的字符两端不自动添加空格，初始设置是 |/|、|\|、
%   - (|U+002D|) 和 \textendash\ (|U+2013|)。
% \end{function}
%
% \subsection{标点符号的处理}
%
% \pkg{xeCJK} 对标点符号的输出宽度的调整是通过调整其左边或右边的空白宽度来实现的。
% 按照目前的处理方式，对于位于左边的标点符号（如左引号），\pkg{xeCJK} 只能调整它
% 左边的空白；对于位于右边的标点符号（如右引号），\pkg{xeCJK} 只能调整它右边的空
% 白；对于居中的标点符号，则调整其左右空白，以保证其居中。对于标点符号的相关设置，
% 只能在导言区中进行。
%
% \subsubsection{设置特定标点符号的宽度和间距}
% \label{subsec:punct}
%
% 这里的设置可用于除 |plain| 以外的所有标点处理格式。
%
% \begin{function}[EXP,updated=2013-08-22]{\xeCJKsetwidth}
%   \begin{syntax}
%     \tn{xeCJKsetwidth}  \Arg{标点列表} \Arg{length}
%     \tn{xeCJKsetwidth} * \Arg{标点列表} \Arg{length}
%   \end{syntax}
%   \meta{标点列表}可以是单个标点，也可以是多个标点。例如，
%   \begin{verbatim}
%     \xeCJKsetwidth{。？}{0.7em}
%   \end{verbatim}
%   将设置句号和问号所占的宽度为 |0.7 em|。带星号的命令，设置标点符号出现在行首/尾
%   时的宽度。
% \end{function}
%
% \begin{function}[EXP]{\xeCJKsetkern}
%   \begin{syntax}
%     \tn{xeCJKsetkern} \Arg{前标点} \Arg{后标点} \Arg{length}
%   \end{syntax}
%   \pkg{xeCJK} 会根据选定的标点处理格式自动调整相邻的前后两个 |CJK| 标点符号的
%   空白宽度。如果需要对个别情况进行特殊调整，可以使用这个命令。例如，
%   \begin{verbatim}
%     \xeCJKsetkern{：}{“}{0.3em}
%   \end{verbatim}
%   将设置冒号与左双引号之间的空白宽度为 |0.3 em|。
% \end{function}
%
% \subsubsection{定义标点符号处理格式}
% \label{subsec:punctstyle}
%
% \begin{function}[EXP,updated=2013-08-22]{\xeCJKDeclarePunctStyle}
%   \begin{syntax}
%     \tn{xeCJKDeclarePunctStyle} \Arg{style} \Arg{options}
%   \end{syntax}
%   定义新的标点符号处理格式，已经存在的同名格式将被覆盖。可以设置的选项将在下面介绍。
% \end{function}
%
% \begin{function}[EXP,updated=2013-08-22]{\xeCJKEditPunctStyle}
%   \begin{syntax}
%     \tn{xeCJKEditPunctStyle} \Arg{style} \Arg{options}
%   \end{syntax}
%   修改已有的标点符号处理格式。\strut
% \end{function}
%
% 下面是可以设置的标点符号格式选项。其中左边一栏是选项名称，中间是选项的输入值类
% 型，右边则是相关说明。某些选项之间是互斥的，具有优先级关系。要使下一级的选项有
% 效，则需要先禁用上一级的设置：对于 \meta{boolean} 类型的选项，将其设置为 |false|，
% 对于 \meta{length} 类型的选项，将其设置为 \tn{maxdimen}，而对于 \meta{real} 类型
% 的选项，将其设置为 |nan|。
%
% \begin{optiondesc}
%   \PSKeyVal{enabled-global-setting}{boolean}
%     是否使用 \tn{xeCJKsetup} 的 |PunctWidth|、|PunctBoundWidth| 选项和
%     \tn{xeCJKsetwidth}、\tn{xeCJKsetkern} 的设置。默认值是 |true|。
% \end{optiondesc}
%
% \begin{optiondesc}
%   \PSKeyVal{fixed-punct-width}{length}
%     设置单个标点符号的宽度。默认值是 \tn{maxdimen}。
%   \PSKeyVal{fixed-punct-ratio}{real}
%     设置单个标点符号的输出宽度与实际宽度的比例。默认值是 |1.0|。
%   \PSKeyVal{mixed-punct-width}{length}
%     设置句末标点符号的宽度。其中句末标点符号通过 \tn{xeCJKsetup} 的 |KaiMingPunct|
%     来设置。默认值是与 |fixed-punct-width| 选项的值相同。
%   \PSKeyVal{mixed-punct-width}{real}
%     设置句末标点符号的宽度比例。默认值是与 |fixed-punct-ratio| 选项的值相同。
%   \PSKeyVal{middle-punct-width}{length}
%     设置居中标点符号的宽度。其中居中标点符号通过 \tn{xeCJKsetup} 的 |MiddlePunct|
%     来设置。默认值是与 |fixed-punct-width| 选项的值相同。
%   \PSKeyVal{middle-punct-width}{real}
%     设置居中标点符号的宽度比例。默认值是与 |fixed-punct-ratio| 选项的值相同。
% \end{optiondesc}
%
% 以上三个选项设置的是标点的固定宽度或比例，\pkg{xeCJK} 会根据设定的选项计算标点符号
% 左/右的空白宽度。下面的选项设置的是标点符号左/右的空白宽度或比例，因此不同标点符号
% 的宽度可能会不同。为了使下面的选项生效，需要先禁用上面的相应选项。优先级自上而下。
%
% \begin{optiondesc}
%   \PSKeyVal{fixed-margin-width}{length}
%     设置标点的左/右空白宽度。默认值是 \tn{maxdimen}。
%   \PSKeyVal{fixed-margin-ratio}{real}
%     设置标点的左/右空白宽度与字体中该标点的相应实际边界宽度的比例。默认值是~|1.0|。
%   \PSKeyVal{mixed-margin-width}{length}
%     设置句末标点的左/右空白宽度。默认值是与 |fixed-margin-width| 的值相同。
%   \PSKeyVal{mixed-margin-ratio}{real}
%     设置句末标点的左/右空白宽度的比例。默认值是与 |fixed-margin-ratio| 的值相同。
%   \PSKeyVal{middle-margin-width}{length}
%     设置居中标点的两边空白宽度。默认值是与 |fixed-margin-width| 的值相同。
%   \PSKeyVal{middle-margin-ratio}{real}
%     设置居中标点的两边空白宽度之和与两边实际两边边界宽度之和的比例。
%     默认值是与 |fixed-margin-ratio| 的值相同。
% \end{optiondesc}
%
% 下面选项设置标点符号出现在行首或者行尾时的宽度或比例。
%
% \begin{optiondesc}
%   \PSKeyVal{bound-punct-width}{length}
%   设置标点符号出现在行首/尾时的宽度。默认值是 \tn{maxdimen}。
%   \PSKeyVal{bound-punct-ratio}{real}
%   设置标点符号出现在行首/尾时的输出宽度与实际宽度的比例。默认值是 |nan|。
%   \PSKeyVal{bound-margin-width}{length}
%   设置标点符号出现在行首/尾时的左/右空白宽度。默认值是 \tn{maxdimen}。
%   \PSKeyVal{bound-margin-ratio}{real}
%   设置标点符号出现在行首/尾时的左/右空白宽度与相应实际边界宽度的比例。默认值是 |0|。
%   \PSKeyVal{enabled-hanging}{boolean}
%   当以上选项的计算结果得到的宽度小于标点符号的实际边界宽度时，是否允许标点符号
%   悬挂出页面边界。默认值是 |false|。
% \end{optiondesc}
%
% \begin{optiondesc}
%   \PSKeyVal{add-min-bound-to-margin}{boolean}
%     是否在以上计算结果的基础上再加上标点的左右实际边界宽度中的最小值。这个选项
%     对居中的标点无效。默认值是 |false|。
% \end{optiondesc}
%
% \begin{optiondesc}
%   \PSKeyVal{optimize-margin}{boolean}
%     使用以上设置空白宽度或比例的选项时，最终输出的标点符号左/右的空白宽度可能大
%     于原来的实际边界宽度。若此时本选项被设置为 |true|，则使用原来的实际边界宽度。
%     而使用 |fixed-punct-width| 选项计算得出的左/右宽度可能小于该标点的另一侧宽
%     度，若此时本选项被启用，则使用该标点的另一侧宽度。默认值为 |false|。
% \end{optiondesc}
%
% \begin{optiondesc}
%   \PSKeyVal{margin-minimum}{length}
%     指定标点符号左/右的最小空白宽度。当经过以上选项设置的空白宽度小于这个选项的值
%     时，则使用这个选项的值。默认值是 |0 pt|。
% \end{optiondesc}
%
% 下面的选项处理的是前后相邻的两个标点符号之间的空白宽度。这些选项是互斥的，优先级
% 自上而下。
%
% \begin{optiondesc}
%   \PSKeyVal{enabled-kerning}{boolean}
%     是否调整前后相邻的两个标点之间的空白宽度。如果设置为 |false|，则每个标点都按
%     原来的输出宽度输出。默认值是 |true|。
%   \PSKeyVal{min-bound-to-kerning}{boolean}
%     是否使用当前字体中前面标点实际左右边界的最小值与后面标点实际左右边界的最小值
%     中的最大值作为两个标点之间的空白宽度。默认值是 |false|。
%   \PSKeyVal{kerning-total-width}{length}
%     设置两个标点的总共宽度。此时 \pkg{xeCJK} 会自动计算两个标点之间的空白宽度。
%     默认值是 \tn{maxdimen}。
%   \PSKeyVal{kerning-total-ratio}{real}
%     设置两个标点的总共输出宽度与实际宽度的比例。默认值是 |0.75|。
%   \PSKeyVal{same-align-margin}{length}
%     前后两个标点位于同侧时，它们之间的空白宽度。默认值是 \tn{maxdimen}。
%   \PSKeyVal{same-align-ratio}{real}
%     前后两个标点位于同侧时，它们之间的空白宽度与实际输出宽度的比例。默认值是~|nan|。
%   \PSKeyVal{different-align-margin}{length}
%     前后两个标点位于异侧时，它们之间的空白宽度。默认值是 \tn{maxdimen}。
%   \PSKeyVal{different-align-ratio}{real}
%     前后两个标点位于异侧时，它们之间的空白宽度与实际输出宽度的比例。默认值是~|nan|。
%   \PSKeyVal{kerning-margin-width}{length}
%     设置前后两个标点之间的空白宽度。默认值是 \tn{maxdimen}。
%   \PSKeyVal{kerning-margin-ratio}{real}
%     设置前后两个标点之间的空白宽度与实际输出空白的比例。默认值是 |1.0|。
% \end{optiondesc}
%
% \begin{optiondesc}
%   \PSKeyVal{optimize-kerning}{boolean}
%     使用以上选项计算出两个标点之间的空白宽度可能小于通过 |min-bound-to-kerning|
%     选项得出的结果。当出现这一情况时，若此选项被设置为 |true|，则使用该选项的空
%     白宽度。默认值为 |false|。
% \end{optiondesc}
%
% \begin{optiondesc}
%   \PSKeyVal{kerning-margin-minimum}{length}
%     指定两个标点之间的最小空白宽度。当经过以上选项设置的空白宽度小于这个选项的值
%     时，则使用这个选项的值。默认值是 |0 pt|。
% \end{optiondesc}
%
% 事实上，\pkg{xeCJK} 的默认设置就相当于中文全角（|quanjiao|）格式。可以使用上面
% 说明的选项定义新的标点处理格式。例如，使用
% \begin{verbatim}
% \xeCJKDeclarePunctStyle { mine }
%   {
%     fixed-punct-ratio       = nan ,
%     fixed-margin-width      = 0 pt ,
%     mixed-margin-width      = \maxdimen ,
%     mixed-margin-ratio      = 0.5 ,
%     middle-margin-width     = \maxdimen ,
%     middle-margin-ratio     = 0.5 ,
%     add-min-bound-to-margin = true ,
%     bound-punct-width       = 0 em ,
%     enabled-hanging         = true ,
%     min-bound-to-kerning    = true ,
%     kerning-margin-minimum  = 0.1 em
%   }
% \end{verbatim}
% 就定义了一个名为 |mine| 的标点处理格式。可以在通过
% \begin{verbatim}
% \xeCJKsetup{PunctStyle=mine}
% \end{verbatim}
% 在文档中使用这个格式。它的意义是：使用标点符号的实际左右边界中的最小值作为其左/右
% 空白的宽度，对于句末标点和居中标点，再加上实际边界空白的一半；当标点出现在行首或
% 行尾时宽度为零，允许悬挂出页面边界；使用相邻两个标点的实际边界中的较小值作为它们
% 之间的空白宽度，并且最小的空白宽度是 |0.1 em|。再例如，使用
% \begin{verbatim}
% \xeCJKEditPunctStyle { hangmobanjiao } { enabled-global-setting = false }
% \end{verbatim}
% 将使得 \tn{xeCJKsetkern} 等的设置对 |hangmobanjiao| 这一格式无效。
%
% \subsection{\pkg{xeCJKfntef} 用法说明}
%
% \pkg{xeCJK} 包含有一个子宏包 \pkg{xeCJKfntef}，可以用它来实现\CJKunderdot{汉字加点}%
% 和可断行的下划线等。它是 \pkg{CJKfntef} 宏包在 \XeLaTeX 下的替换版本，基本用法完全一致。
%
% \pkg{xeCJKfntef} 基于 \package{ulem} 宏包，除了兼容 \pkg{ulem} 定义的一些命令外，
% 还进行了一些扩充：
%
% \begin{function}[updated=2014-11-04]
%  {\CJKunderline,\CJKunderdblline,\CJKunderwave,\CJKsout,\CJKxout}
%   \begin{syntax}
%     \tn{CJKunderline} [*] [-] \oarg{选项} \Arg{内容}
%   \end{syntax}
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.35\linewidth,gobble=6]
%     \CJKunderline{虚室生白，吉祥止止}\\
%     \CJKunderdblline{虚室生白，吉祥止止}\\
%     \CJKunderwave{虚室生白，吉祥止止}\\
%     \CJKsout{虚室生白，吉祥止止}\\
%     \CJKxout{虚室生白，吉祥止止}
%   \end{SideBySideExample}
% \end{function}
%
% \csappto{NoHighlight@Attributes}{\catcode37=14\relax}
%
% \begin{Example}[frame=single,numbers=left,gobble=4]
%   \CJKunderline-{南朝}\CJKunderline-{梁}\CJKunderline-{劉勰}%
%   \CJKunderwave-{文心雕龍}\CJKunderwave-{養氣}\\
%   \CJKunderline*[thickness=1pt, hidden=true]{瞻彼阕者，虚室生白，吉祥止止}
% \end{Example}
%
% \begin{function}[updated=2014-11-04]{\CJKunderdot}
%   \begin{syntax}
%     \tn{CJKunderdot} \oarg{选项} \Arg{内容}
%   \end{syntax}
%   在汉字下加点，可以和上述下划线命令嵌套使用。例如\smallskip
%
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.35\linewidth,gobble=6]
%     \CJKunderline{虚室生白，\CJKunderdot{吉祥}止止}\\
%     \CJKunderdot{虚室生白，\CJKunderline{吉祥}止止}
%   \end{SideBySideExample}
% \end{function}
%
% \medskip
%
% 对上述六种对象，\pkg{xeCJKfntef} 提供了一些选项，设置点或线的位置和颜色。可以用
% \tn{xeCJKsetup} 预先统一设置它们，也可以在使用时特别设置。
%
% \begin{function}[added=2014-11-04]{skip}
%   \begin{syntax}
%     \tn{xeCJKsetup} \{ underline/skip = \meta{\TTF} \}
%     \tn{xeCJKsetup} \{ underline = \{ skip = \meta{\TTF} , ... \} \}
%   \end{syntax}
%   默认情况下，下划线会自动跳过中文标点符号，可以设置本选项为 \texttt{false}，
%   禁用这一功能。相应下划线命令后加上 |*| 号，具有相同的效果。
% \end{function}
%
% \begin{function}{subtract}
%   设置本选项为 \texttt{true}，使得下划线的首尾减少一定距离，避免前后的下划线
%   连在一起，适用于古籍标点整理中的专名号和书名号。在相应下划线命令后加上 |-|
%   号，具有相同的效果。
% \end{function}
%
% \begin{function}{hidden}
%   设置本选项为 \texttt{true}，将隐藏文本内容，只画下划线。
% \end{function}
%
% \begin{function}{format}
%   \begin{syntax}
%     \tn{xeCJKsetup} \{ underline/format = \tn{color}\{red\} \}
%     \tn{xeCJKsetup} \{ underwave = \{ format = \tn{color}\{red\}, ... \} \}
%   \end{syntax}
%   设置线或点的格式，比如颜色。
% \end{function}
%
% \begin{function}{symbol}
%   设置 \tn{CJKunderwave} 或 \tn{CJKunderdot} 的符号。
% \end{function}
%
% \smallskip
%
% 例如，波浪线 \tn{CJKunderwave} 的符号不会随字号而变化，在小字号下不好看。我们可以
% 将它改为随字号而变化大小：
%
% \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.35\linewidth,gobble=4]
%   % \usepackage{fix-cm}
%   \xeCJKsetup{%
%     underwave/symbol=
%       \fontsize{0.5em}{0pt}%
%       \fontencoding{U}\fontfamily{lasy}\selectfont
%       \char 58\relax}
%   \footnotesize
%   \CJKunderwave{瞻彼阕者，虚室生白，吉祥止止}
% \end{SideBySideExample}
%
% \begin{function}{thickness}
%   设置 \tn{CJKunderline}、\tn{CJKunderdblline} 和 \tn{CJKsout} 的线的厚度。
%   初始值是 \tn{ULthickness}。
% \end{function}
%
% \begin{function}{depth}
%   设置线或点的深度（基线到线或点的顶部的距离）。初始值都是 \texttt{0.2em}。
% \end{function}
%
% \begin{function}{boxdepth}
%   \tn{CJKunderdot} 可能会影响到行距，可以设置本选项进行调整。如果不希望
%   \tn{CJKunderdot} 影响行距，可以将本选项设置为 \texttt{0pt}。
% \end{function}
%
% \begin{function}{sep}
%   设置 \tn{CJKunderdot} 与 \tn{CJKunderline}、\tn{CJKunderdblline} 或
%   \tn{CJKunderwave} 嵌套使用时，点与线或者线与点的距离。
% \end{function}
%
% \begin{function}{gap}
%   设置 \tn{CJKunderdblline} 的两条线之间的距离。初始值是 \texttt{1.1pt}。
% \end{function}
%
% \begin{function}{height}
%   设置删除线 \tn{CJKsout} 的高度（线的中心到基线的距离）。初始值是 \texttt{0.35em}。
% \end{function}
%
% \smallskip
%
% 例如，我们可以设置 \tn{CJKsout} 的厚度和颜色，让它具有类似高亮的效果：
%
% \begin{Example}[frame=single,numbers=left,gobble=4]
%   \CJKsout*[thickness=2.5ex, format=\color{yellow}]{瞻彼阕者，虚室生白，吉祥止止}
% \end{Example}
%
% \medskip
%
% \pkg{xeCJKfntef} 还提供给了自定义下划线和符号的 \tn{CJKunderanyline} 和
% \tn{CJKunderanysymbol}。
%
% \begin{function}[updated=2014-11-07]{\CJKunderanyline}
%   \begin{syntax}
%     \tn{CJKunderanyline} [*] [-] \oarg{选项} \Arg{深度} \Arg{下划内容} \Arg{文本内容}
%   \end{syntax}
%   \pkg{xeCJKfntef} 先将 \meta{下划内容} 放进一个盒子（\tn{xeCJKfntefbox}）里，然后
%   向下移动 \meta{深度} 给定的距离，再用于填充。可用的 \meta{选项} 是
%   \texttt{skip}、\texttt{hidden}、\texttt{subtract}、\texttt{sep} 和
%   \texttt{boxdepth}。选项 \texttt{sep} 和 \texttt{boxdepth} 的初始值是空，表示
%   禁用该选项的功能。可以在 \tn{xeCJKsetup} 中通过对象 \texttt{ulem} 来设置。
% \end{function}
%
% \smallskip
%
% 例如，高亮效果也可以如下实现：
%
% \begin{Example}[frame=single,numbers=left,gobble=4]
%   \CJKunderanyline*{0.5ex}{\color{yellow}\rule{2pt}{2.5ex}}{虚室生白，吉祥止止}
% \end{Example}
%
% \begin{function}[updated=2014-11-04]{\CJKunderanysymbol}
%   \begin{syntax}
%     \tn{CJKunderanysymbol} \oarg{选项} \Arg{深度} \Arg{符号} \Arg{文本内容}
%   \end{syntax}
%   \pkg{xeCJKfntef} 将 \meta{符号} 放进一个盒子（\tn{xeCJKfntefbox}）里。
%   \meta{深度} 参数用于设置盒子顶部的深度（基线到盒子顶部的距离）。
%   可用的 \meta{选项} 是 \texttt{sep} 和 \texttt{boxdepth}，意义与
%   \tn{CJKunderdot} 的相同。
% \end{function}
%
% \smallskip
%
% 例如，给汉字加三角形，可以如下设置：
%
% \begin{Example}[frame=single,numbers=left,gobble=4]
%   \CJKunderanysymbol[sep=0.1em]{0.2em}{\tiny$\triangle$}
%     {瞻彼阕者，虚室生白，\CJKunderline{吉祥止止}}
% \end{Example}
%
% \begin{function}[updated=2014-11-07]{\xeCJKfntefon}
%   \begin{syntax}
%     \tn{xeCJKfntefon} [*] [-] \oarg{选项}
%   \end{syntax}
%   功能与用法 \pkg{ulem} 宏包的 \tn{ULon} 相同，扩展了可选参数符号 |*| 和 |-|，
%   可用的 \meta{选项} 是 \texttt{skip}、\texttt{hidden} 和 \texttt{subtract}。
%   这三个选项对 \pkg{ulem} 宏包定义的 \tn{uline} 等命令也有效，需要在
%   \tn{xeCJKsetup} 中通过对象 \texttt{ulem} 来设置。例如\smallskip
%
%   \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.35\linewidth,gobble=6]
%     \xeCJKsetup{ulem/skip=true}
%     \uline{虚室生白，吉祥止止}
%   \end{SideBySideExample}
% \end{function}
%
% \smallskip
%
% 此外，\pkg{xeCJKfntef} 还提供了指定宽度，让汉字分散对齐的的环境
% \env{CJKfilltwosides} 和 \env{CJKfilltwosides*}。
%
% \begin{function}[updated=2014-11-04]{CJKfilltwosides}
%   \begin{syntax}
%     \tn{begin}\{CJKfilltwosides\} \oarg{位置} \Arg{宽度}
%       文本内容\verb=\\=
%       文本内容
%     \tn{end}\{CJKfilltwosides\}
%   \end{syntax}
%   环境中的内容被放入垂直盒子中，可选参数 \meta{位置} 指定盒子的基线位置。
%   可以使用 \texttt{t}（顶部）、\texttt{c}（居中）和 \texttt{b}（底部），默认是 \texttt{c}。
%   \meta{宽度} 参数指定盒子的宽度。
%   \env{CJKfilltwosides*} 环境与 \env{CJKfilltwosides} 的区别是，当 \meta{宽度}
%   不大于零或者不大于盒子的自然宽度时，就取盒子的自然宽度。例如
% \end{function}
%
% \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.5\linewidth,gobble=4]
%   \begin{CJKfilltwosides}{.8\linewidth}
%     瞻彼阕者，\\
%     虚室生白，吉祥止止
%   \end{CJKfilltwosides}
% \end{SideBySideExample}
%
% \begin{SideBySideExample}[frame=single,numbers=left,xrightmargin=.5\linewidth,gobble=4]
%   \begin{CJKfilltwosides*}{0pt}
%     瞻彼阕者，\\
%     虚室生白，吉祥止止
%   \end{CJKfilltwosides*}
% \end{SideBySideExample}
%
% \subsection{其它}
% \label{subsec:others}
%
% \begin{function}[updated=2013-11-16]{\xeCJKVerbAddon,\xeCJKOffVerbAddon}
%   调整文字间距以便于让 CJK 字符占的宽度等于西文等宽字体中两个空格的宽度。如果这两
%   个空格的宽度小于当前 CJK 正常文字的宽度，将对 CJK 字体进行适当地缩小。这有利于
%   等宽字体的代码对齐等情形。需要注意的是，\tn{xeCJKVerbAddon} 对 \pkg{xeCJK} 的内
%   部进行了比较大的修改，使用它之后，将禁止在 CJK 字符类之间自动换行，这与西文在
%   抄录环境中的情况是一致的。所以不应该单独使用，应该放在分组里限制其作用域，否则
%   是无效的。当然它可以和其它关于代码抄录的宏包配合使用。例如，可以使用于
%   \package{fancyvrb} 宏包的 \texttt{formatcom} 选项。此时设置的西文字体应该确实
%   是等宽的以保证对齐。若西文等宽字体发生变动（包括字体大小），则需要在其后面使用
%   \tn{xeCJKVerbAddon}，重新计算间距的宽度。\tn{xeCJKOffVerbAddon}
%   用于在使用 \tn{xeCJKVerbAddon} 的环境中局部取消它的作用。由于 \package{listings}
%   宏包有自己的代码对齐机制，所以 \tn{xeCJKVerbAddon} 在由 \pkg{listings} 定义的
%   代码环境中无效。
% \end{function}
%
% \begin{function}[added=2012-12-03]{\xeCJKnobreak}
%   \begin{syntax}
%     ……汉字。\tn{xeCJKnobreak}\tn{footnote}\{脚注\}
%   \end{syntax}
%   \tn{xeCJKnobreak} 用在全角标点符号后面，目的是确保不能在此处断行。如果已经启用了
%   前面介绍的 |CheckFullRight| 选项，则不需要再用此命令。
% \end{function}
%
% \begin{function}[added=2013-11-09]{\xeCJKShipoutHook}
%   \pkg{xeCJK} 在正文中的一些特殊设置（汉字下加点、在 \env{verbatim} 或
%   \env{lstlisting} 环境中分页）可能会影响到 \TeX 的输出例行程序（output routine）
%   中的内容（比如页眉和页脚）。\tn{xeCJKShipoutHook} 用于恢复正文中的普通设置。
%   \pkg{xeCJK} 已经处理了页眉和页脚的情况，其它的就需要根据情况自行调用。
%   比如若使用 \pkg{eso-pic} 或者 \pkg{atbegshi} 实现文字水印，并且正文中使用了
%   以上所列的特殊形式，就需要在命令 \tn{AtBeginShipout} 的参数的最前面使用
%   \tn{xeCJKShipoutHook}。
% \end{function}
%
% \section{已知问题和兼容性}
%
% \XeTeX 在配置文件 \file{unicode-letters.tex} 中将所有 CJK 表意文字的 \tn{catcode}
% 设置为 $11$。因此汉字可以直接用作控制序列的名字，但是当汉字出现在控制序列后面的
% 时候，要用空格分隔开，否则就会出现“\texttt{! Undefined control sequence.}”的错误。
%
% \pkg{xeCJK} 使用并重新定义了 \pkg{CJK} 宏包的部分宏命令，如 \tn{CJKfamily}、
% \tn{CJKsymbol} 和 \tn{CJKglue} 等。需要指出，\pkg{xeCJK} 不需要 \pkg{CJK}
% 的支持，并且 \pkg{xeCJK} 自动禁止在它之后载入 \pkg{CJK} 宏包。
% 可以在 \pkg{xeCJK} 之\emph{后}载入 \pkg{CJKnumb} 宏包，实现数字的中文化，
% 也可以用功能更完善的 \package{zhnumber} 宏包。
%
% \pkg{xeCJK} 进行了一些处理，使得在使用 \XeTeX 时 \package{listings} 宏包可以
% 支持 Unicode，因此在 \texttt{listings} 定义的代码环境中可以直接使用中文，不再
% 需要通过 \texttt{escapechar}。
%
% 新版本（\texttt{3.x}）的 \pkg{xeCJK} 完全使用 \hologo{LaTeX3} 的语法来编写。
% \hologo{LaTeX3} 放弃了 \tn{outer} 宏的概念，因此相关工具在
% 遇到 \tn{outer} 宏时可能会存在问题。按照目前 \pkg{xeCJK} 的实现方式，在 CJK 文字
% 后面遇到 \tn{outer} 宏时会出现类似
% \begin{verbatim}
%   ! Forbidden control sequence found while scanning use of \use_i:nn
% \end{verbatim}
% 的错误。目前已知的有 \package{cprotect} 宏包提供的 \tn{cprotect}。它的定义是
% \begin{verbatim}
%   \outer\long\def\cprotect{\icprotect}
% \end{verbatim}
% 因此，这时可以暂时用 \tn{icprotect} 代替 \tn{cprotect}。事实上，当 \pkg{cprotect}
% 被引入时，\pkg{xeCJK} 将使用
% \begin{verbatim}
%   \let\cprotect\icprotect
% \end{verbatim}
% 来取消 \tn{cprotect} 的外部宏限制。但由于 \tn{cprotect} 的特殊性，应该只在外部
% 使用它，即不要让它出现在任何宏的参数中。其它 \tn{outer} 宏的情况，可以在它前面
% 加上 \tn{relax} 来回避上面的错误。
%
% \pkg{xeCJK} 依赖 \XeTeX 的 \tn{XeTeXinterchartoks} 机制，与使用相同机制的宏包（例如
% \pkg{polyglossia} 和 \pkg{xesearch}）可能会存在大小不一的冲突。
% \pkg{xeCJK} 虽然为此作了一些处理，但与它们共同使用时应该小心。
%
%\end{documentation}
%
%
% \StopEventually{}
%
%
%\begin{implementation}
%
% \section{\pkg{xeCJK} 代码实现}
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=xeCJK>
%    \end{macrocode}
%
% \subsection{运行环境检查}
%
% \pkg{xeCJK} 必须使用 \XeTeX 引擎的支持。
%    \begin{macrocode}
\msg_new:nnn { xeCJK } { Require-XeTeX }
  {
    The~xeCJK~package~requires~XeTeX~to~function.\\\\
    You~must~change~your~typesetting~engine~to~"xelatex" \\
    instead~of~plain~"latex"~or~"pdflatex"~or~"lualatex".\\
    Loading~xeCJK~will~abort!
  }
\xetex_if_engine:F { \msg_critical:nn { xeCJK } { Require-XeTeX } }
%    \end{macrocode}
%
% 应该使用较新版本的 \pkg{expl3} 宏包。
%    \begin{macrocode}
\msg_new:nnn { xeCJK } { 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.\\
    \str_if_eq:nnT {#1} { expl3 } { Loading~xeCJK~will~abort! }
  }
\@ifpackagelater { expl3 } { 2014/07/20 } { }
  { \msg_critical:nnn { xeCJK } { l3-too-old } { expl3 } }
%    \end{macrocode}
%
% \begin{macro}[pTF,internal]{\xeCJK_if_package_loaded:n}
% 判断宏包是否被引入，可用于文档正文中。
%    \begin{macrocode}
\prg_new_conditional:Npnn \xeCJK_if_package_loaded:n #1 { p , T , F , TF }
  {
    \tl_if_exist:cTF { ver@ #1 . \c_@@_package_ext_tl }
      { \prg_return_true: } { \prg_return_false: }
  }
\tl_const:Nx \c_@@_package_ext_tl { \@pkgextension }
%    \end{macrocode}
% \end{macro}
%
% 下面这些 \pkg{CJK} 系列宏包不应该被使用。
%    \begin{macrocode}
\msg_new:nnn { xeCJK } { incompatible-package }
  {
    The~`#1'~package~and~xeCJK~are~incompatible.\\\\
    Please~do~not~use~it.
  }
\msg_new:nnn { xeCJK } { after-package }
  {
    The~`#1'~package~and~xeCJK~are~incompatible.\\\\
    Please~load~it~after~xeCJK.
  }
\clist_map_inline:nn { CJKfntef , CJKnumb }
  {
    \xeCJK_if_package_loaded:nT {#1}
      { \msg_error:nnn { xeCJK } { after-package } {#1} }
  }
\clist_map_inline:nn { CJKulem , CJKvert , CJKpunct , CJKutf8 , CJK }
  {
    \xeCJK_if_package_loaded:nTF {#1}
      { \msg_error:nnn { xeCJK } { incompatible-package } {#1} }
      { \tl_const:cn { ver@ #1 . \c_@@_package_ext_tl } { 9999/99/99 } }
  }
%    \end{macrocode}
%
% 以下日期以前的 \pkg{xtemplate} 宏包关于 \tn{KeyValue} 的 Bug 会影响到后面
% 标点符号的处理。
%    \begin{macrocode}
\RequirePackage { xtemplate }
\@ifpackagelater { xtemplate } { 2012/11/10 } { }
  { \msg_error:nnn { xeCJK } { l3-too-old } { xtemplate } }
%    \end{macrocode}
%
%    \begin{macrocode}
\RequirePackage { xparse , l3keys2e }
%    \end{macrocode}
%
% \subsection{内部工具}
%
% 分配临时变量。
%    \begin{macrocode}
\tl_new:N \l_@@_tmp_tl
\int_new:N \l_@@_tmp_int
\box_new:N \l_@@_tmp_box
\dim_new:N \l_@@_tmp_dim
\bool_new:N \l_@@_tmp_bool
\skip_new:N \l_@@_tmp_skip
\clist_new:N \l_@@_tmp_clist
%    \end{macrocode}
%
% \begin{macro}[internal]
%  {\@@_msg_new:nn ,\@@_error:n,\@@_error:nx,\@@_warning:nx,\@@_info:nxx}
% 各种信息函数的缩略形式。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_msg_new:nn   { \msg_new:nnn       { xeCJK } }
\cs_new_protected_nopar:Npn \@@_msg_new:nnn  { \msg_new:nnnn      { xeCJK } }
\cs_new_protected_nopar:Npn \@@_error:n      { \msg_error:nn      { xeCJK } }
\cs_new_protected_nopar:Npn \@@_error:nx     { \msg_error:nnx     { xeCJK } }
\cs_new_protected_nopar:Npn \@@_warning:n    { \msg_warning:nn    { xeCJK } }
\cs_new_protected_nopar:Npn \@@_warning:nx   { \msg_warning:nnx   { xeCJK } }
\cs_new_protected_nopar:Npn \@@_warning:nxx  { \msg_warning:nnxx  { xeCJK } }
\cs_new_protected_nopar:Npn \@@_warning:nxxx { \msg_warning:nnxxx { xeCJK } }
\cs_new_protected_nopar:Npn \@@_info:nxx     { \msg_info:nnxx     { xeCJK } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_allow_break:,\xeCJK_no_break:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_allow_break: { \tex_penalty:D \c_zero }
\cs_new_protected_nopar:Npn \xeCJK_no_break: { \tex_penalty:D \c_ten_thousand }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%  {\@@_at_end_preamble:n,\@@_after_preamble:n,\@@_after_end_preamble:n}
%  在 \tn{document} 前后加上各种钩子。
%    \begin{macrocode}
\tl_new:N \g_@@_at_end_preamble_hook_tl
\tl_new:N \g_@@_after_preamble_hook_tl
\tl_new:N \g_@@_after_end_preamble_hook_tl
\cs_new_protected:Npn \@@_at_end_preamble:n #1
  { \tl_gput_right:Nn \g_@@_at_end_preamble_hook_tl {#1} }
\cs_new_protected:Npn \@@_after_preamble:n #1
  { \tl_gput_right:Nn \g_@@_after_preamble_hook_tl {#1} }
\cs_new_protected:Npn \@@_after_end_preamble:n #1
  { \tl_gput_right:Nn \g_@@_after_end_preamble_hook_tl {#1} }
\xeCJK_if_package_loaded:nTF { etoolbox }
  {
    \AtEndPreamble { \g_@@_at_end_preamble_hook_tl }
    \AfterPreamble { \g_@@_after_preamble_hook_tl }
    \AfterEndPreamble { \g_@@_after_end_preamble_hook_tl }
  }
  {
    \AtBeginDocument { \g_@@_after_preamble_hook_tl }
    \cs_new_protected_nopar:Npn \@@_document_left_hook:
      { \group_end: \g_@@_at_end_preamble_hook_tl \group_begin: }
    \cs_new_protected_nopar:Npn \@@_document_right_hook:
      { \scan_stop: \g_@@_after_end_preamble_hook_tl \tex_ignorespaces:D }
    \cs_gset_nopar:Npx \document
      {
        \@@_document_left_hook:
        \exp_not:o { \document }
        \@@_document_right_hook:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.7}{2013/11/09}{使用 \pkg{everypage} 往 \tn{shipout} 盒子里加钩子。}
% \changes{v3.2.16}{2014/12/16}{不再依赖 \pkg{everypage} 宏包。}
%
% \begin{macro}{\xeCJKShipoutHook}
% 在 \tn{shipout} 盒子里加钩子，可以影响到页眉页脚。\tn{AtBeginDvi} 将参数保存在
% 盒子中，而 \pkg{atbegshi} 的 \tn{AtBeginShipout} 在 \tn{shipout} 盒子构建好之后
% 才起作用，所以它们都影响不到页眉页脚。我们通过往 \tn{@begindvi} 里加入钩子来完成。
% 注意，第一次使用 \tn{@begindvi} 之后，它会将自身定义为 \tn{@empty}。
%    \begin{macrocode}
\@@_after_preamble:n
  { \tl_put_right:Nn \@begindvi { \xeCJK@first@begindvi } }
\cs_new_protected_nopar:Npn \xeCJK@first@begindvi
  {
    \xeCJKShipoutHook
    \cs_if_exist:NTF \@begindvi
      { \tl_gput_right:Nn }
      { \tl_const:Nn }
    \@begindvi { \xeCJKShipoutHook }
  }
\NewDocumentCommand \xeCJKShipoutHook { }
  {
    \bool_if:NF \l_@@_shipout_hook_bool
      {
        \bool_set_true:N \l_@@_shipout_hook_bool
        \tl_use:N \l_@@_shipout_hook_tl
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_add_to_shipout:n}
% \changes{v3.2.11}{2014/03/14}{不再使用内部名字。}
% 往 \tn{shipout} 盒子中加入钩子。
%    \begin{macrocode}
\cs_new_protected:Npn \xeCJK_add_to_shipout:n
  { \tl_put_right:Nn \l_@@_shipout_hook_tl }
\tl_new:N \l_@@_shipout_hook_tl
\bool_new:N \l_@@_shipout_hook_bool
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_reverse:nnn}
% |#1| 为 |#2| 或 |#3|，若 |#1| 和 |#2| 相等，则返回 |#3|，否则返回 |#2|。
%    \begin{macrocode}
\cs_new_nopar:Npn \xeCJK_reverse:nnn #1#2#3
  { \str_if_eq_x:nnTF {#1} {#2} {#3} {#2} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
% {\xeCJK_tl_remove_outer_braces:N,\xeCJK_tl_remove_outer_braces:n}
% \changes{v3.2.4}{2013/07/02}{去掉外层分组括号时，移除空格，避免死循环。}
% 去掉 |#1| 外层的分组括号。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_tl_remove_outer_braces:N #1
  { \tl_set:Nx #1 { \exp_args:NV \xeCJK_tl_remove_outer_braces:n #1 } }
\cs_new:Npn \xeCJK_tl_remove_outer_braces:n #1
  {
    \exp_last_unbraced:Nf
    \@@_tl_remove_outer_braces:w { \tl_trim_spaces:n {#1} } \s__stop
  }
\cs_new:Npn \@@_tl_remove_outer_braces:w #1 \s__stop
  {
    \bool_if:nTF { \tl_if_single_p:n {#1} && ! ( \tl_if_head_is_N_type_p:n {#1} ) }
      { \xeCJK_tl_remove_outer_braces:n {#1} }
      { \tl_trim_spaces:n {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_cs_clear:N,\xeCJK_cs_gclear:N}
% 让控制序列的意义为空。
%    \begin{macrocode}
\cs_new_protected:Npn \xeCJK_cs_clear:N #1
  { \cs_set_eq:NN #1 \prg_do_nothing: }
\cs_new_protected:Npn \xeCJK_cs_gclear:N #1
  { \cs_gset_eq:NN #1 \prg_do_nothing: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_swap_cs:NN}
% 交换 |#1| 和 |#2| 的意义。
%    \begin{macrocode}
\cs_new_protected:Npn \xeCJK_swap_cs:NN #1#2
  {
    \cs_set_eq:NN \@@_swap_cs_aux:w #1
    \cs_set_eq:NN #1 #2
    \cs_set_eq:NN #2 \@@_swap_cs_aux:w
    \cs_undefine:N \@@_swap_cs_aux:w
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_font_gset_to_current:c}
% |#1| 是控制序列的名字，令它等于当前字体命令。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_font_gset_to_current:c #1
  {
    \exp_after:wN \cs_gset_eq:NN
    \cs:w #1 \exp_after:wN \cs_end: \tex_the:D \tex_font:D
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal,pTF]{\xeCJK_glyph_if_exist:N}
% \changes{v3.1.0}{2012/11/19}{改进 \pkg{fontspec} 宏包中定义的
% \cs{font_glyph_if_exist:NnTF}。}
% 判断当前字体中是否含有字符 |#1|。\pkg{fontspec} 中的类似函数在判断为真的时候，
% 会留有一个 \cs{scan_stop:}，造成不必要的边界，同时也不完全可展。因此，我们重新
% 定义它。
%    \begin{macrocode}
\prg_new_conditional:Npnn \xeCJK_glyph_if_exist:N #1 { p , T , F , TF }
  {
    \etex_iffontchar:D \tex_font:D `#1 \exp_stop_f:
      \prg_return_true: \else: \prg_return_false: \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal,var]{\c_xeCJK_space_skip_tl}
% \changes{v3.1.0}{2012/11/18}{字间空格考虑 \tn{spaceskip} 不为零的情况。}
% \changes{v3.2.0}{2013/05/22}{字间空格考虑到 \tn{spacefactor} 和 \tn{xspaceskip} 的情况。}
% 当前字体状态下，一个字间空格产生的 |glue| 的长度，包括伸展和收缩部分。
%    \begin{macrocode}
\tl_const:Nn \c_xeCJK_space_skip_tl
  {
    \int_compare:nNnTF \g_@@_spacefactor_int = \c_one_thousand
      {
        \skip_if_eq:nnTF \tex_spaceskip:D \c_zero_skip
          {
            \tex_fontdimen:D \c_two \tex_font:D
              plus  \tex_fontdimen:D \c_three \tex_font:D
              minus \tex_fontdimen:D \c_four  \tex_font:D
          }
          { \tex_spaceskip:D }
      }
      {
        \skip_if_eq:nnTF \tex_spaceskip:D \c_zero_skip
          {
            \int_compare:nNnTF \g_@@_spacefactor_int < { 2000 }
              { \_@@_space_skip_scale:nnn { \tex_fontdimen:D \c_two \tex_font:D } }
              {
                \skip_if_eq:nnTF \tex_xspaceskip:D \c_zero_skip
                  {
                    \_@@_space_skip_scale:nnn
                      {
                        \tex_fontdimen:D \c_two   \tex_font:D +
                        \tex_fontdimen:D \c_seven \tex_font:D
                      }
                  }
                  { \tex_xspaceskip:D  \use_none:nn }
              }
              { \tex_fontdimen:D \c_three \tex_font:D }
              { \tex_fontdimen:D \c_four  \tex_font:D }
          }
          {
            \int_compare:nNnTF \g_@@_spacefactor_int < { 2000 }
              { \_@@_space_skip_scale:nnn { \tex_spaceskip:D } }
              {
                \skip_if_eq:nnTF \tex_xspaceskip:D \c_zero_skip
                  {
                    \_@@_space_skip_scale:nnn
                      { \tex_spaceskip:D + \tex_fontdimen:D \c_seven \tex_font:D }
                  }
                  { \tex_xspaceskip:D \use_none:nn }
              }
              { \etex_gluestretch:D \tex_spaceskip:D }
              { \etex_glueshrink:D  \tex_spaceskip:D }
          }
      }
  }
\cs_new_nopar:Npn \_@@_space_skip_scale:nnn #1#2#3
  {
    \dim_eval:n {#1}
    plus \fp_eval:n { \g_@@_spacefactor_int / 1000 } #2
    minus
      \int_div_truncate:nn
        { 1000 * \tex_number:D #3 } { \g_@@_spacefactor_int } sp
  }
\int_new:N \g_@@_spacefactor_int
\int_gset_eq:NN \g_@@_spacefactor_int \c_one_thousand
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_glue_to_skip:nN}
% 取得一个 |glue| 的长度，包括伸展和收缩部分。如果参数不是 |glue|，则取其宽度。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_glue_to_skip:nN #1#2
  {
    \group_begin:
    \hbox_set:Nw \l_@@_tmp_box #1 \scan_stop:
    \int_compare:nNnTF \etex_lastnodetype:D = \c_eleven
      {
        \exp_after:wN \hbox_set_end: \exp_after:wN \group_end: \exp_after:wN
        \skip_set:Nn \exp_after:wN #2 \exp_after:wN
          { \skip_use:N \tex_lastskip:D }
      }
      {
        \hbox_set_end: \exp_after:wN \group_end: \exp_after:wN
        \skip_set:Nn \exp_after:wN #2 \exp_after:wN
           { \dim_use:N \box_wd:N \l_@@_tmp_box }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF,internal]{\xeCJK_if_blank_x:n}
% 判断是否为空或者仅含一个空格。
%    \begin{macrocode}
\prg_new_conditional:Npnn \xeCJK_if_blank_x:n #1 { p , T , F , TF }
  {
    \if_case:w \pdftex_strcmp:D { } {#1} \exp_stop_f:
      \prg_return_true:
    \else:
      \if_case:w \pdftex_strcmp:D { ~ } {#1} \exp_stop_f:
        \prg_return_true: \else: \prg_return_false: \fi:
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_int_until_do:nn,\@@_int_until_do:wn}
% 由于定义较为简单，可以比 \cs{int_until_do:nNnn} 稍微快一点点。
%    \begin{macrocode}
\cs_new_protected:Npn \xeCJK_int_until_do:nn #1#2
  { \@@_int_until_do:wn \use_none:n { \reverse_if:N \if_int_compare:w #1#2 } }
\cs_new_protected:Npn \@@_int_until_do:wn \use_none:n #1
  { #1 \exp_after:wN \@@_int_until_do:wn \fi: \use_none:n {#1} }
\int_new:N \l_@@_begin_int
\int_new:N \l_@@_end_int
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_peek_catcode_ignore_spaces:NTF}
% \changes{v3.1.1}{2012/12/04}{新增有省略空格标识的 \texttt{peek} 函数。}
% 我们在里面设置了一个变量 \cs{l_@@_peek_ignore_spaces_bool} 用于标识后面的空格
% 是否被省略掉了。
%    \begin{macrocode}
\cs_new_protected:Npn \xeCJK_peek_catcode_ignore_spaces:NTF #1#2#3
  {
    \cs_set_eq:NN \l__peek_search_token #1 \scan_stop:
    \tl_set:Nn \@@_peek_catcode_true:w  { \group_align_safe_end: #2 }
    \tl_set:Nn \@@_peek_catcode_false:w { \group_align_safe_end: #3 }
    \bool_set_false:N \l_@@_peek_ignore_spaces_bool
    \group_align_safe_begin:
    \peek_after:Nw \@@_peek_catcode_ignore_spaces_branches:w
  }
\cs_new_protected_nopar:Npn \@@_peek_catcode_ignore_spaces_branches:w
  {
    \if_meaning:w \l_peek_token \c_space_token
      \bool_set_true:N \l_@@_peek_ignore_spaces_bool
      \exp_after:wN \peek_after:Nw
      \exp_after:wN \@@_peek_catcode_ignore_spaces_branches:w
      \tex_romannumeral:D 0
    \else:
      \if_catcode:w
        \exp_not:N \l_peek_token \exp_not:N \l__peek_search_token
        \exp_after:wN \exp_after:wN
        \exp_after:wN \@@_peek_catcode_true:w
      \else:
        \exp_after:wN \exp_after:wN
        \exp_after:wN \@@_peek_catcode_false:w
      \fi:
    \fi:
  }
\tl_new:N \@@_peek_catcode_true:w
\tl_new:N \@@_peek_catcode_false:w
\bool_new:N \l_@@_peek_ignore_spaces_bool
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_peek_after_ignore_spaces:nw}
% 与 \tn{@ifnextchar} 和 \tn{futurenonspacelet} 类似，会省略掉后面的空格。
%    \begin{macrocode}
\cs_new_protected:Npn \xeCJK_peek_after_ignore_spaces:nw #1
  {
    \tl_set:Nn \@@_peek_after_do:w { \group_align_safe_end: #1 }
    \group_align_safe_begin:
    \peek_after:Nw \@@_peek_ignore_spaces_branches:w
  }
\cs_new_protected_nopar:Npn \@@_peek_ignore_spaces_branches:w
  {
    \if_meaning:w \l_peek_token \c_space_token
      \exp_after:wN \peek_after:Nw
      \exp_after:wN \@@_peek_ignore_spaces_branches:w
      \tex_romannumeral:D 0
    \else:
      \exp_after:wN \@@_peek_after_do:w
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_token_value_class:N}
% 用于取得记号 |#1| 所在的 \XeTeX 字符类。|#1| 应为 \tn{catcode} 为 |11| 或 |12|
% 的显性或隐性记号。
%    \begin{macrocode}
\cs_new_nopar:Npn \xeCJK_token_value_class:N #1
  { \XeTeXcharclass \xeCJK_token_value_charcode:N #1 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_token_value_charcode:N}
% \changes{v3.2.4}{2013/06/30}{考虑 \texttt{charcode} 超出 BMP 的情况。}
% 当记号 |#1| 的 \texttt{charcode} 大于等于 \texttt{0x10000} 时，\XeTeX\
% \texttt{0.9999.0} 版以前的 \tn{meaning} 的返回结果比较特殊\footnote{参见
% \url{http://tug.org/pipermail/xetex/2013-January/023967.html} 和
% \url{http://tex.stackexchange.com/a/64848}。}，需要特别处理。同时使用较新版本中
% 提供的原语设置 \texttt{mathcode}。目前，\texttt{0.9999.0} 版以后的 \XeTeX 的
% \tn{meaning} 对于超出 BMP 的字符，会返回两个字符，分别对应于其 UTF-16 编码的
% 首尾代理。\footnote{参见 \url{http://tug.org/pipermail/xetex/2013-June/024543.html}。}
%    \begin{macrocode}
\cs_new_nopar:Npn \xeCJK_token_value_charcode:N #1
  { \exp_after:wN \@@_token_value_charcode:w \token_to_meaning:N #1 \q_stop }
\fp_compare:nNnTF { \int_use:N \xetex_XeTeXversion:D \XeTeXrevision } > { 0.9998 }
  {
    \cs_new_nopar:Npn \@@_token_value_charcode:w #1 ~ #2 ~ #3#4 \q_stop
      {
        \int_eval:n
          {
            \tl_if_empty:nTF {#4}
              { `#3 }
              { ( `#3 - "D800 ) * "400 + ( `#4 - "DC00 ) + "10000 }
          }
      }
    \cs_new_eq:NN \xeCJK_xetex_mathcode:w \Umathcode
  }
  {
    \cs_new_nopar:Npn \@@_token_value_charcode:w #1 ~ #2 ~ #3#4 \q_stop
      { \int_eval:n { \tl_if_empty:nTF {#4} { `#3 } { "20000 } } }
    \cs_new_eq:NN \xeCJK_xetex_mathcode:w \XeTeXmathcode
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF,internal]{\xeCJK_if_CJK_class:N}
% 判断字符 |#1| 是否为 CJK 字符类，包括文字和标点符号。
%    \begin{macrocode}
\prg_new_conditional:Npnn \xeCJK_if_CJK_class:N #1 { p , T , F , TF }
  {
    \if_cs_exist:w \@@_CJK_class_tl:n { \xeCJK_token_value_class:N #1 } \cs_end:
      \prg_return_true: \else: \prg_return_false: \fi:
  }
\cs_new_nopar:Npn \@@_CJK_class_tl:n #1
  { c_@@_CJK_class_ \int_eval:n {#1} _tl }
\cs_generate_variant:Nn \@@_CJK_class_tl:n { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF,internal]{\xeCJK_if_same_class:NN}
% 判断两个字符是否同属于一个字符类。
%    \begin{macrocode}
\prg_new_conditional:Npnn \xeCJK_if_same_class:NN #1#2 { p , T , F , TF }
  {
    \if_int_compare:w
      \xeCJK_token_value_class:N #1 = \xeCJK_token_value_class:N #2 \exp_stop_f:
      \prg_return_true: \else: \prg_return_false: \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{功能开关}
%
% \begin{macro}{xeCJKactive}
% 事实上，将开启或关闭 \XeTeX 的整个字符类机制。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    xeCJKactive .choice: ,
    xeCJKactive / true  .code:n = { \makexeCJKactive   } ,
    xeCJKactive / false .code:n = { \makexeCJKinactive } ,
    xeCJKactive      .default:n = { true }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\makexeCJKactive, \makexeCJKinactive}
%    \begin{macrocode}
\NewDocumentCommand \makexeCJKactive   { } { \XeTeXinterchartokenstate = \c_one  }
\NewDocumentCommand \makexeCJKinactive { } { \XeTeXinterchartokenstate = \c_zero }
%    \end{macrocode}
% \end{macro}
%
% 抑制 |BOM|。
%    \begin{macrocode}
\char_set_catcode_ignore:n { "FEFF }
%    \end{macrocode}
%
% \subsection{字符类别设定}\label{sec:xeCJK-class-set}
%
% \begin{macro}[internal,var]{\g_@@_class_seq,\g_@@_new_class_seq}
% 分别用于记录在 \pkg{xeCJK} 中使用的字符类别名称和新建的字符类别的编号。
%    \begin{macrocode}
\seq_new:N \g_@@_class_seq
\seq_new:N \g_@@_new_class_seq
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_new_class:n}
% 新建一个字符类别。|#1| 是自定义名称。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_new_class:n #1
  {
    \int_if_exist:cTF { \@@_class_csname:n {#1} }
      { \@@_error:nx { class-already-defined } {#1} }
      {
        \exp_args:Nc \newXeTeXintercharclass { \@@_class_csname:n {#1} }
        \clist_new:c { g_@@_#1_range_clist }
        \seq_gput_right:Nn \g_@@_class_seq {#1}
        \seq_gput_right:Nv \g_@@_new_class_seq { \@@_class_csname:n {#1} }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_save_class:nn}
% \changes{v3.1.1}{2012/12/06}
% {使用 \cs{xeCJK_save_class:nn} 保存 \XeTeX 预定义的字符类别。}
% 保存 \XeTeX 预定义的字符类别。|#1| 是自定义名称，|#2| 是编号。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_save_class:nn #1#2
  {
    \int_if_exist:cTF { \@@_class_csname:n {#1} }
      { \@@_error:nx { class-already-defined } {#1} }
      {
        \int_const:cn { \@@_class_csname:n {#1} } {#2}
        \clist_new:c { g_@@_#1_range_clist }
        \seq_gput_right:Nn \g_@@_class_seq {#1}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_class_csname:n}
% 字符类名称对应的控制序列名字。
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_class_csname:n #1 { c_@@_#1_class_int }
\cs_new_eq:cN { \@@_class_csname:n { Others } } \l_@@_tmp_int
\@@_msg_new:nn { class-already-defined }
  {
    XeTeX~character~class~`#1'~has~been~already~defined.\\\\
    Please~take~another~name. \\
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.0}{2013/05/20}{增加 \texttt{IVS} 字符类用于处理异体字选择符。}
%
% \pkg{xeCJK} 需要以下字符类别用于字符输出。其中 |Default|、|CJK|、|FullLeft|、
% |FullRight|、|Boundary| 为 \XeTeX\ 中预定义的类别，\pkg{xeCJK} 新增加了\
% |HalfLeft|、|HalfRight|、|NormalSpace| 和 |IVS|。其中异体字选择符
% (Ideographic Variation Selectors)\footnote{\url{http://www.unicode.org/reports/tr37/}}
% 需要 \XeTeX\ |0.9999.0| 以上的版本^^A
% \footnote{\url{http://tug.org/pipermail/xetex/2013-March/024118.html}}和相关字体的支持。
% \begin{center}\xeCJKsetup{PunctStyle=hangmobanjiao}
% \begin{tabular}{cll}
% \toprule
%   类别        & 说明               & 例子 \\ \midrule
% |Default|     & 西文一般符号       & abc123 \\
% |CJK|         & CJK 表意符号       & 汉字ぁぃぅ \\
% |FullLeft|    & 全角左标点         & （《：“ \\
% |FullRight|   & 全角右标点         & ，。）》” \\
% |HalfLeft|    & 半角左标点         & ( [ \{ \\
% |HalfRight|   & 半角右标点         & , . ? ) ] \} \\
% |NormalSpace| & 前后原始间距的符号 & / \\
% |Boundary|    & 边界               & 空格 \\
% |IVS|         & 异体字选择符       & “回字有四样写法”\\
% |HangulJamo|  & 朝鲜文字母         & |ᄻ||ᆟ||ᇫ|\\
% \bottomrule
% \end{tabular}
% \end{center}
%
% \begin{macro}[internal]{Default,CJK,FullLeft,FullRight,Boundary}
% 这五类是 \XeTeX\ 预定义的类别。
%    \begin{macrocode}
\xeCJK_save_class:nn { Default }   { \c_zero  }
\xeCJK_save_class:nn { CJK }       { \c_one   }
\xeCJK_save_class:nn { FullLeft }  { \c_two   }
\xeCJK_save_class:nn { FullRight } { \c_three }
\xeCJK_save_class:nn { Boundary }  { \c_two_hundred_fifty_five }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.15}{2014/11/10}{增加 \texttt{HangulJamo} 字符类。}
%
% \begin{macro}[internal]{HalfLeft,HalfRight,NormalSpace,IVS,HangulJamo}
% 新增西文半角左/右标点、前后原始间距的符号和异体字选择符类。
%    \begin{macrocode}
\xeCJK_new_class:n { HalfLeft }
\xeCJK_new_class:n { HalfRight }
\xeCJK_new_class:n { NormalSpace }
\xeCJK_new_class:n { IVS }
\xeCJK_new_class:n { HangulJamo }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.11}{2014/04/10}
% {左右角括号 \texttt{U+2329} 和 \texttt{U+232A} 是西文标点符号。}
% \changes{v3.2.15}{2014/11/09}
% {把 REVERSE SOLIDUS（\texttt{U+005C}）、HYPHEN-MINUS（\texttt{U+002D}）和
%  EN DASH（\texttt{U+2013}）归入 \texttt{NormalSpace} 类。}
%
% \begin{macro}[var,internal]
%  {\c_@@_HalfLeft_chars_clist,\c_@@_HalfRight_chars_clist,\c_@@_NormalSpace_chars_clist}
% \hypertarget{CJKcharclass}{西文半角左/右标点和前后原始间距的字符类。}
%    \begin{macrocode}
\clist_const:Nn \c_@@_HalfLeft_chars_clist
  { "28  , "5B , "60 , "7B , "2329 }
\clist_const:Nn \c_@@_HalfRight_chars_clist
  { "21 , "22 , "25 , "27 , "29 , "2C , "2E , "3A , "3B , "3F , "5D , "7D , "232A }
\clist_const:Nn \c_@@_NormalSpace_chars_clist { "2D , "2F , "5C , "2013 }
%    \end{macrocode}
% \end{macro}
%
% 以下对全角标点符号的归类来源于 \XeTeX 的脚本
% \href{http://sourceforge.net/p/xetex/code/ci/master/tree/source/texk/web2c/xetexdir/unicode-char-prep.pl}
% {\file{unicode-char-prep.pl}} 和 Unicode 数据库\footnote{\url{http://www.unicode.org/reports/tr14/}}。
%
% \changes{v3.2.3}{2013/06/09}{根据 \XeTeX 的脚本重新整理全角标点符号。}
%
% \begin{macro}[var,internal]{\c_@@_OP_chars_clist}
% Open Punctuation (OP)
% \PrintPunctList{OP}{Open Punctuation}
% 以下代码的第一行是中西文共用的左引号。
%    \begin{macrocode}
\clist_const:Nn \c_@@_OP_chars_clist
  {
    "2018 , "201C ,
    "3008 , "300A , "300C , "300E , "3010 , "3014 , "3016 , "3018 , "301A , "301D ,
    "FE17 , "FE35 , "FE37 , "FE39 , "FE3B , "FE3D , "FE3F , "FE41 , "FE43 , "FE47 ,
    "FE59 , "FE5B , "FE5D , "FF08 , "FF3B , "FF5B , "FF5F , "FF62
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\c_@@_PR_chars_clist}
% \changes{v3.3.0}{2014/12/26}{不把 \texttt{U+20A9} 归入 CJK 的 PR 类。}
% Prefix Numeric (PR)
% \PrintPunctList{PR}{Prefix Numeric}
%    \begin{macrocode}
\clist_const:Nn \c_@@_PR_chars_clist
  { "FE69 , "FF04 , "FFE1 , "FFE5 , "FFE6 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\c_@@_FullLeft_chars_clist}
% 以上两类标点符号出现在文字的左边，不应出现在行尾位置。
%    \begin{macrocode}
\clist_const:Nx \c_@@_FullLeft_chars_clist
  {
    \c_@@_OP_chars_clist ,
    \c_@@_PR_chars_clist
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\c_@@_CL_chars_clist}
% Close Punctuation (CL)
% \PrintPunctList{CL}{Close Punctuation}
% 以下代码的第一行是中西文共用的一些标点符号。
%    \begin{macrocode}
\clist_const:Nn \c_@@_CL_chars_clist
  {
    "00B7 , "2019 , "201D , "2014 , "2015 , "2025 , "2026 , "2027 , "2500 ,
    "3001 , "3002 , "3009 , "300B , "300D , "300F , "3011 , "3015 , "3017 , "3019 ,
    "301B , "301E , "301F , "FE11 , "FE12 , "FE18 , "FE36 , "FE38 , "FE3A , "FE3C ,
    "FE3E , "FE40 , "FE42 , "FE44 , "FE48 , "FE50 , "FE52 , "FE5A , "FE5C , "FE5E ,
    "FF09 , "FF0C , "FF0E , "FF3D , "FF5D , "FF60 , "FF61 , "FF63 , "FF64
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.3.0}{2014/12/26}{不把 NS 类中的一些有禁则的日文归入 FullRight 类。}
%
% \begin{macro}[var,internal]{\c_@@_NS_chars_clist}
% Nonstarter (NS)
% \PrintPunctList{NS}{Nonstarter}
% \noindent Hyphens (cl-03)
% \PrintPunctList{hyphens}{Hyphens}
% \noindent Iteration marks (cl-09)
% \PrintPunctList{iteration_marks}{Iteration marks}
% 根据 W3C 的资料\footnote{\url{http://www.w3.org/TR/jlreq/}}，\texttt{cl-03} 和
% \texttt{cl-09} 在非常松散的情况下可以没有禁则。我们就不把它们当成标点来处理禁则，
% 避免间距错误。
%    \begin{macrocode}
\clist_const:Nn \c_@@_hyphens_chars_clist { "301C , "30A0 }
\clist_const:Nn \c_@@_iteration_marks_chars_clist
  { "3005 , "303B , "309D , "309E , "30FD , "30FE }
\clist_const:Nn \c_@@_NS_chars_clist
  { "30FB , "FE54 , "FE55 , "FF1A , "FF1B , "FF65 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\c_@@_EX_chars_clist}
% Exclamation/Interrogation (EX)
% \PrintPunctList{EX}{Exclamation/Interrogation}
%    \begin{macrocode}
\clist_const:Nn \c_@@_EX_chars_clist
  { "FE15 , "FE16 , "FE56 , "FE57 , "FF01 , "FF1F }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\c_@@_IS_chars_clist}
% Infix Numeric Separator (IS)
% \PrintPunctList{IS}{Infix Numeric Separator}
%    \begin{macrocode}
\clist_const:Nn \c_@@_IS_chars_clist { "FE10 , "FE13 , "FE14 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\c_@@_CJ_chars_clist}
% Conditional Japanese Starter (CJ)。这类字符的禁则是可选的^^A
% \footnote{\url{https://code.google.com/p/ctex-kit/issues/detail?id=166}}，
% 为实现的简单计，我们把它们归入 CJK 类，即没有禁则。
% \PrintPunctList{CJ}{Conditional Japanese Starter}
%    \begin{macrocode}
\clist_const:Nn \c_@@_CJ_chars_clist
  {
    "3041 , "3043 , "3045 , "3047 , "3049 , "3063 , "3083 , "3085 , "3087 , "308E ,
    "3095 , "3096 , "30A1 , "30A3 , "30A5 , "30A7 , "30A9 , "30C3 , "30E3 , "30E5 ,
    "30E7 , "30EE , "30F5 , "30F6 , "30FC , "31F0 , "31F1 , "31F2 , "31F3 , "31F4 ,
    "31F5 , "31F6 , "31F7 , "31F8 , "31F9 , "31FA , "31FB , "31FC , "31FD , "31FE ,
    "31FF , "FF67 , "FF68 , "FF69 , "FF6A , "FF6B , "FF6C , "FF6D , "FF6E , "FF6F ,
    "FF70
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\c_@@_PO_chars_clist}
% Postfix Numeric (PO)
% \PrintPunctList{PO}{Postfix Numeric}
%    \begin{macrocode}
\clist_const:Nn \c_@@_PO_chars_clist { "FE6A , "FF05 , "FFE0 }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.3.0}{2014/12/26}{不把小写日文假名归入 FullRight 类。}
%
% \begin{macro}[var,internal]{\c_@@_FullRight_chars_clist}
% 以上六类标点符号出现在文字的右边，不应出现在行首位置。
%    \begin{macrocode}
\clist_const:Nx \c_@@_FullRight_chars_clist
  {
    \c_@@_CL_chars_clist ,
    \c_@@_NS_chars_clist ,
    \c_@@_EX_chars_clist ,
    \c_@@_IS_chars_clist ,
    \c_@@_PO_chars_clist
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\c_@@_CJK_chars_clist}
% CJK 字符类，包括文字和标点符号。
%    \begin{macrocode}
\clist_const:Nn \c_@@_CJK_chars_clist
  {
%    \end{macrocode}
% \begin{itemize}[nosep,leftmargin=0pt]
% \item CJK Radicals Supplement （中日韩部首补充）
%    \begin{macrocode}
    "2E80 -> "2EFF ,
%    \end{macrocode}
% \item Kangxi Radicals （康熙部首）
%    \begin{macrocode}
    "2F00 -> "2FDF ,
%    \end{macrocode}
% \item Ideographic Description Characters （表意文字描述符）
%    \begin{macrocode}
    "2FF0 -> "2FFF ,
%    \end{macrocode}
% \item CJK Symbols and Punctuation （中日韩符号和标点）
%    \begin{macrocode}
    "3000 -> "303F ,
%    \end{macrocode}
% \item Hiragana （日文平假名）
%    \begin{macrocode}
    "3040 -> "309F ,
%    \end{macrocode}
% \item Katakana （日文片假名）
%    \begin{macrocode}
    "30A0 -> "30FF ,
%    \end{macrocode}
% \item Bopomofo （注音字母）
%    \begin{macrocode}
    "3100 -> "312F ,
%    \end{macrocode}
% \item Hangul Compatibility Jamo （谚文兼容字母）
%    \begin{macrocode}
    "3130 -> "318F ,
%    \end{macrocode}
% \item Kanbun （象形字注释标志）
%    \begin{macrocode}
    "3190 -> "319F ,
%    \end{macrocode}
% \item Bopomofo Extended （注音字母扩展）
%    \begin{macrocode}
    "31A0 -> "31BF ,
%    \end{macrocode}
% \item CJK Strokes （中日韩笔画）
%    \begin{macrocode}
    "31C0 -> "31EF ,
%    \end{macrocode}
% \item Katakana Phonetic Extensions （日文片假名语音扩展）
%    \begin{macrocode}
    "31F0 -> "31FF ,
%    \end{macrocode}
% \item Enclosed CJK Letters and Months （带圈中日韩字母和月份）
%    \begin{macrocode}
    "3200 -> "32FF ,
%    \end{macrocode}
% \item CJK Compatibility （中日韩兼容）
%    \begin{macrocode}
    "3300 -> "33FF ,
%    \end{macrocode}
% \item CJK Unified Ideographs Extension-A （中日韩统一表意文字扩展 A）
%    \begin{macrocode}
    "3400 -> "4DBF ,
%    \end{macrocode}
% \item Yijing Hexagrams Symbols （易经六十四卦符号）
%    \begin{macrocode}
    "4DC0 -> "4DFF ,
%    \end{macrocode}
% \item CJK Unified Ideographs （中日韩统一表意文字）
%    \begin{macrocode}
    "4E00 -> "9FFF ,
%    \end{macrocode}
% \item Yi Syllables （彝文音节）
%    \begin{macrocode}
    "A000 -> "A48F ,
%    \end{macrocode}
% \item Yi Radicals （彝文字根）
%    \begin{macrocode}
    "A490 -> "A4CF ,
%    \end{macrocode}
% \item Hangul Syllables （谚文音节）
%    \begin{macrocode}
    "AC00 -> "D7AF ,
%    \end{macrocode}
% \item CJK Compatibility Ideographs （中日韩兼容表意文字）
%    \begin{macrocode}
    "F900 -> "FAFF ,
%    \end{macrocode}
% \item Vertical Forms （竖排形式）
%    \begin{macrocode}
    "FE10 -> "FE1F ,
%    \end{macrocode}
% \item CJK Compatibility Forms （中日韩兼容形式）
%    \begin{macrocode}
    "FE30 -> "FE4F ,
%    \end{macrocode}
% \item Halfwidth and Fullwidth Forms （半角及全角形式）
%    \begin{macrocode}
    "FF00 -> "FFEF ,
%    \end{macrocode}
% \item Kana Supplement （日文假名增补）
%    \begin{macrocode}
    "1B000 -> "1B0FF ,
%    \end{macrocode}
% \item Enclosed Ideographic Supplement （带圈表意文字增补）
%    \begin{macrocode}
    "1F200 -> "1F2FF ,
%    \end{macrocode}
% \item CJK Unified Ideographs Extension-B （中日韩统一表意文字扩展 B）
%    \begin{macrocode}
    "20000 -> "2A6DF ,
%    \end{macrocode}
% \item CJK Unified Ideographs Extension-C （中日韩统一表意文字扩展 C）
%    \begin{macrocode}
    "2A700 -> "2B73F ,
%    \end{macrocode}
% \item CJK Unified Ideographs Extension-D （中日韩统一表意文字扩展 D）
%    \begin{macrocode}
    "2B740 -> "2B81F ,
%    \end{macrocode}
% \item CJK Compatibility Ideographs Supplement （中日韩兼容表意文字增补）
%    \begin{macrocode}
    "2F800 -> "2FA1F
%    \end{macrocode}
% \end{itemize}
%    \begin{macrocode}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\c_@@_IVS_chars_clist}
% 包括日文假名浊点和异体字选择符。
%    \begin{macrocode}
\clist_const:Nn \c_@@_IVS_chars_clist
  {
%    \end{macrocode}
% \begin{itemize}[nosep,leftmargin=0pt]
% \item 日文假名浊点
%    \begin{macrocode}
    "3099 -> "309A ,
%    \end{macrocode}
% \item Variation Selectors （异体字选择符）
%    \begin{macrocode}
    "FE00 -> "FE0F ,
%    \end{macrocode}
% \item Variation Selectors Supplement （异体字选择符增补）
%    \begin{macrocode}
    "E0100 -> "E01EF
%    \end{macrocode}
% \end{itemize}
%    \begin{macrocode}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\c_@@_HangulJamo_chars_clist}
% 朝鲜文字母。
%    \begin{macrocode}
\clist_const:Nn \c_@@_HangulJamo_chars_clist
  {
%    \end{macrocode}
% \begin{itemize}[nosep,leftmargin=0pt]
% \item Hangul Jamo （谚文字母）
%    \begin{macrocode}
    "1100 -> "11FF ,
%    \end{macrocode}
% \item Hangul Jamo Extended-A （谚文扩展 A）
%    \begin{macrocode}
    "A960 -> "A97F ,
%    \end{macrocode}
% \item Hangul Jamo Extended-B （谚文扩展 B）
%    \begin{macrocode}
    "D7B0 -> "D7FF
%    \end{macrocode}
% \end{itemize}
%    \begin{macrocode}
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{字符类别处理}
%
% \begin{macro}[internal,var]
%  {\g_@@_base_class_seq,\g_@@_non_CJK_class_seq,\g_@@_CJK_class_seq}
%    \begin{macrocode}
\seq_new:N \g_@@_base_class_seq
\seq_gset_eq:NN \g_@@_base_class_seq \g_@@_class_seq
\seq_new:N \g_@@_non_CJK_class_seq
\seq_gset_from_clist:Nn \g_@@_non_CJK_class_seq
  { Default , HalfLeft , HalfRight , NormalSpace , Boundary }
\seq_new:N \g_@@_CJK_class_seq
\cs_new_protected_nopar:Npn \@@_save_CJK_class:n #1
  {
    \seq_gput_right:Nn \g_@@_CJK_class_seq {#1}
    \tl_const:cn { \@@_CJK_class_tl:c { \@@_class_csname:n {#1} } } {#1}
  }
\clist_map_function:nN
  { CJK , FullLeft , FullRight , IVS , HangulJamo } \@@_save_CJK_class:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_class_num:n}
% |#1| 为字符类别名称，用于取得字符类别对应的编号。
%    \begin{macrocode}
\cs_new_nopar:Npn \xeCJK_class_num:n #1 { \use:c { \@@_class_csname:n {#1} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKDeclareCharClass}
%    \begin{macrocode}
\NewDocumentCommand \xeCJKDeclareCharClass { s > { \TrimSpaces } m m }
  {
    \xeCJK_declare_char_class:nx {#2} {#3}
    \IfBooleanT {#1} { \xeCJKResetPunctClass }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_declare_char_class:nn,\@@_set_char_class_aux:Nnw}
% 用于设置字符所属的类别，|#1| 为类别名称，|#2| 为字符的 |Unicode|，相邻字符用
% 半角逗号隔开，支持类似 |"1100 -> "11FF| 起止范围的使用方式。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_declare_char_class:nn #1#2
  {
    \clist_set:Nn \l_@@_tmp_clist {#2}
    \clist_gconcat:ccN
      { g_@@_#1_range_clist } { g_@@_#1_range_clist } \l_@@_tmp_clist
    \clist_map_inline:Nn \l_@@_tmp_clist
      {
        \str_if_eq:nnF {##1} { -> }
          {
            \@@_set_char_class_aux:Nnw \xeCJK_set_char_class:nnn {##1}
              { \xeCJK_class_num:n {#1} }
          }
      }
    \xeCJK_set_char_class:nnn { "3099 } { "309A } { \xeCJK_class_num:n { IVS } }
  }
\NewDocumentCommand \@@_set_char_class_aux:Nnw
  { m > { \SplitArgument { 1 } { -> } } m } { #1 #2 }
\cs_generate_variant:Nn \clist_gconcat:NNN { cc }
\cs_generate_variant:Nn \xeCJK_declare_char_class:nn { nx , nV }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_check_num_range:nnNN}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_check_num_range:nnNN #1#2#3#4
  {
    \bool_if:nTF { \xeCJK_if_blank_x_p:n {#1} || \xeCJK_if_blank_x_p:n {#2} }
      {
        \int_set:Nn #3 { \xeCJK_if_blank_x:nTF {#1} {#2} {#1} }
        \int_set_eq:NN #3 #4
      }
      {
        \int_set:Nn #3 { \int_min:nn {#1} { \IfNoValueTF {#2} {#1} {#2} } }
        \int_set:Nn #4 { \int_max:nn {#1} { \IfNoValueTF {#2} {#1} {#2} } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.3}{2013/06/08}{不再改变 CJK 字符类的 \tn{catcode}。}
% \changes{v3.2.7}{2013/08/29}{修正 \file{unicode-letters.tex} 中谚文符号
% \tn{catcode} 不准的问题。}
%    \begin{macrocode}
\int_set:Nn \l_@@_begin_int { "AC00 }
\int_set:Nn \l_@@_end_int   { "D7A3 }
\xeCJK_int_until_do:nn { \l_@@_begin_int > \l_@@_end_int }
  {
    \char_set_catcode_letter:n { \l_@@_begin_int }
    \int_incr:N \l_@@_begin_int
  }
%    \end{macrocode}
%
% \begin{macro}[internal]{\xeCJK_set_char_class:nnn}
% \changes{v3.1.1}{2012/12/05}{在文档中设置字符类别时不重复设置 \tn{catcode}。}
% 设置字符类别，|#1| 和 |#2| 为字符类别起止的 |Unicode|，|#3| 为类别名称对应编号。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_set_char_class:nnn #1#2#3
  {
    \@@_check_num_range:nnNN {#1} {#2} \l_@@_begin_int \l_@@_end_int
    \int_set:Nn \l_@@_tmp_int {#3}
    \xeCJK_int_until_do:nn { \l_@@_begin_int > \l_@@_end_int }
      {
        \XeTeXcharclass \l_@@_begin_int = \l_@@_tmp_int
        \int_incr:N \l_@@_begin_int
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_set_char_class_eq:nn}
% \changes{v3.1.1}{2012/12/06}{交换参数的顺序。}
% 将字符类 |#1| 中的字符全部设置成字符类 |#2|。只适用于 |#1| 的字符类范围为离散的
% 逗号列表的情况。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_set_char_class_eq:nn #1#2
  {
    \int_set:Nn \l_@@_tmp_int { \xeCJK_class_num:n {#2} }
    \clist_map_inline:cn { c_@@_#1_chars_clist }
      { \XeTeXcharclass ##1 = \l_@@_tmp_int }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\normalspacedchars}
% 声明前后不加间距的字符。
%    \begin{macrocode}
\NewDocumentCommand \normalspacedchars { m }
  {
    \tl_map_inline:nn {#1}
      { \XeTeXcharclass `##1 = \xeCJK_class_num:n { NormalSpace } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKResetPunctClass}
% 用于重置标点符号所属的字符类。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKResetPunctClass { }
  {
    \xeCJK_declare_char_class:nV { HalfLeft  } \c_@@_HalfLeft_chars_clist
    \xeCJK_declare_char_class:nV { HalfRight } \c_@@_HalfRight_chars_clist
    \xeCJK_declare_char_class:nV { FullLeft  } \c_@@_FullLeft_chars_clist
    \xeCJK_declare_char_class:nV { FullRight } \c_@@_FullRight_chars_clist
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\xeCJKResetCharClass}
% 用于恢复 \pkg{xeCJK} 对字符类别的设置。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKResetCharClass { }
  {
    \xeCJK_declare_char_class:nV { CJK } \c_@@_CJK_chars_clist
    \xeCJK_declare_char_class:nV { NormalSpace } \c_@@_NormalSpace_chars_clist
    \xeCJK_declare_char_class:nV { IVS } \c_@@_IVS_chars_clist
    \xeCJK_declare_char_class:nV { HangulJamo } \c_@@_HangulJamo_chars_clist
    \xeCJKResetPunctClass
  }
%    \end{macrocode}
% \end{macro}
%
% 设置字符类别。
%    \begin{macrocode}
\xeCJKResetCharClass
%    \end{macrocode}
%
% \begin{macro}[internal]{\xeCJK_inter_class_toks:nnn}
% 在相邻类别之间插入内容。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_inter_class_toks:nnn #1#2#3
  { \XeTeXinterchartoks \xeCJK_class_num:n {#1} ~ \xeCJK_class_num:n {#2} = {#3} }
\cs_generate_variant:Nn \xeCJK_inter_class_toks:nnn { nnc , nnx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_get_inter_class_toks:nn}
% 取出相邻类别之间的内容。
%    \begin{macrocode}
\cs_new_nopar:Npn \xeCJK_get_inter_class_toks:nn #1#2
  { \tex_the:D \XeTeXinterchartoks \xeCJK_class_num:n {#1} ~ \xeCJK_class_num:n {#2} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_clear_inter_class_toks:nn}
% 清除相邻类别之间的内容。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_clear_inter_class_toks:nn #1#2
  { \xeCJK_inter_class_toks:nnn {#1} {#2} { \prg_do_nothing: } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_pre_inter_class_toks:nnn}
% 在相邻类别之间已有的内容前增加内容。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_pre_inter_class_toks:nnn #1#2#3
  {
    \xeCJK_inter_class_toks:nnx {#1} {#2}
      { \exp_not:n {#3} \xeCJK_get_inter_class_toks:nn {#1} {#2} }
  }
\cs_generate_variant:Nn \xeCJK_pre_inter_class_toks:nnn { nnx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_app_inter_class_toks:nnn}
% 在相邻类别之间已有的内容后追加内容。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_app_inter_class_toks:nnn #1#2#3
  {
    \xeCJK_inter_class_toks:nnx {#1} {#2}
      { \xeCJK_get_inter_class_toks:nn {#1} {#2} \exp_not:n {#3} }
  }
\cs_generate_variant:Nn \xeCJK_app_inter_class_toks:nnn { nnc , nnx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_copy_inter_class_toks:nnnn}
% 将 |#3| 和 |#4| 之间的内容复制到 |#1| 和 |#2| 之间。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_copy_inter_class_toks:nnnn #1#2#3#4
  {
    \tl_set:Nx \l_@@_tmp_tl { \xeCJK_get_inter_class_toks:nn {#3} {#4} }
    \tl_if_empty:NF \l_@@_tmp_tl
      { \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:V \l_@@_tmp_tl } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_replace_inter_class_toks:nnnn}
% 将 |#1| 和 |#2| 之间出现的 |#3| 用 |#4| 替换。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_replace_inter_class_toks:nnnn #1#2#3#4
  {
    \tl_set:Nx \l_@@_tmp_tl { \xeCJK_get_inter_class_toks:nn {#1} {#2} }
    \tl_if_empty:NF \l_@@_tmp_tl
      {
        \tl_replace_all:Nnn \l_@@_tmp_tl {#3} {#4}
        \xeCJK_inter_class_toks:nnx {#1} {#2} { \exp_not:V \l_@@_tmp_tl }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_clear_Boundary_and_CJK_toks:}
% 清除边界与 CJK 文字、全角左右标点之间的内容。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_clear_Boundary_and_CJK_toks:
  { \seq_map_function:NN \g_@@_CJK_class_seq \@@_clear_Boundary_and_CJK_toks:n }
\cs_new_protected_nopar:Npn \@@_clear_Boundary_and_CJK_toks:n #1
  { \xeCJK_clear_inter_class_toks:nn { Boundary } {#1} }
%    \end{macrocode}
% \end{macro}
%
% \subsection{字符输出规则}
%
% \begin{center}
% \begin{tabular}{l*9c}
% \toprule
%   & |Default| & |CJK| & |FullL| & |FullR| & |HalfL|
%   & |HalfR| & |Normal| & |Bound| & |IVS| \\ \midrule
% |Default|
%   &
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   &
%   &
%   &
%   & \tokslink{def-bound}
%   & \tokslink{def-IVS}\\
% |CJK|
%   & \tokslink{def-cjk}
%   & \tokslink{cjk-cjk}
%   & \tokslink{cjk-fl-fr}
%   & \tokslink{cjk-fl-fr}
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   & \tokslink{cjk-bound}
%   &\\
% |FullLeft|
%   & \tokslink{def-cjk}
%   & \tokslink{fl-fr-others}
%   & \tokslink{cjk-fl-fr}
%   & \tokslink{cjk-fl-fr}
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   & \tokslink{fl-fr-bound}
%   & \tokslink{def-IVS}\\
% |FullRight|
%   & \tokslink{def-cjk}
%   & \tokslink{fl-fr-others}
%   & \tokslink{cjk-fl-fr}
%   & \tokslink{cjk-fl-fr}
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   & \tokslink{fl-fr-bound}
%   & \tokslink{def-IVS}\\
% |HalfLeft|
%   &
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   &
%   &
%   &
%   &
%   & \tokslink{def-IVS}\\
% |HalfRight|
%   &
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   &
%   &
%   &
%   & \tokslink{def-bound}
%   & \tokslink{def-IVS}\\
% |NormalSpace|
%   &
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   & \tokslink{def-cjk}
%   &
%   &
%   &
%   & \tokslink{ns-bound}
%   & \tokslink{def-IVS}\\
% |Boundary|
%   & \tokslink{bound-def}
%   & \tokslink{bound-cjk}
%   & \tokslink{bound-fl-fr}
%   & \tokslink{bound-fl-fr}
%   & \tokslink{bound-def}
%   &
%   & \tokslink{bound-ns}
%   &
%   & \tokslink{def-IVS}\\
% |IVS|
%   & \tokslink{def-IVS}
%   & \tokslink{def-IVS}
%   & \tokslink{def-IVS}
%   & \tokslink{def-IVS}
%   & \tokslink{def-IVS}
%   & \tokslink{def-IVS}
%   & \tokslink{def-IVS}
%   & \tokslink{def-IVS}
%   & \tokslink{def-IVS}\\
% \bottomrule
% \end{tabular}
% \end{center}
%
% \begin{macro}[internal]{\xeCJK_class_group_begin:,\xeCJK_class_group_end:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_class_group_begin:
  {
    \c_group_begin_token
    \bool_set_true:N \l_@@_CJK_group_bool
    \int_gset_eq:NN \g_@@_spacefactor_int \c_one_thousand
  }
\bool_new:N \l_@@_CJK_group_bool
\cs_new_eq:NN \xeCJK_class_group_end: \c_group_end_token
%    \end{macrocode}
% \end{macro}
%
% \hypertarget{def-IVS}{\texttt{IVS}} 字符类与 |CJK| 字符类基本相同，只是从 |CJK|
% 转移到 |IVS| 时，不加入任何内容。
%    \begin{macrocode}
\AtEndOfPackage
  {
    \seq_map_inline:Nn \g_@@_class_seq
      {
        \str_if_eq:nnTF {#1} { IVS }
          { \xeCJK_copy_inter_class_toks:nnnn { IVS } {#1} { CJK } { CJK } }
          {
            \xeCJK_copy_inter_class_toks:nnnn { IVS } {#1} { CJK } {#1}
            \str_if_eq:nnF {#1} { CJK }
              { \xeCJK_copy_inter_class_toks:nnnn {#1} { IVS } {#1} { CJK } }
          }
      }
  }
%    \end{macrocode}
%
% \hypertarget{def-HJ}{\texttt{HangulJamo}} 字符类与 |CJK| 字符类基本相同，只是
% |HangulJamo| 类之间不加入任何内容。
%    \begin{macrocode}
\AtEndOfPackage
  {
    \seq_map_inline:Nn \g_@@_class_seq
      {
        \str_if_eq:nnF {#1} { HangulJamo }
          {
            \xeCJK_copy_inter_class_toks:nnnn { HangulJamo } {#1} { CJK } {#1}
            \xeCJK_copy_inter_class_toks:nnnn {#1} { HangulJamo } {#1} { CJK }
          }
      }
  }
%    \end{macrocode}
%
% \hypertarget{def-cjk}{}
%    \begin{macrocode}
\clist_map_inline:nn { Default , HalfLeft , HalfRight , NormalSpace }
  {
    \xeCJK_inter_class_toks:nnn {#1} { CJK }
      {
        \xeCJK_class_group_begin:
        \xeCJK_select_font:
        \xeCJK_clear_inter_class_toks:nn {#1} { CJK }
        \xeCJK_clear_Boundary_and_CJK_toks:
        \CJKsymbol
      }
    \xeCJK_inter_class_toks:nnn { CJK } {#1} { \xeCJK_class_group_end: }
  }
%    \end{macrocode}
%
% \hypertarget{bound-def}{}
%    \begin{macrocode}
\clist_map_inline:nn { Default , HalfLeft }
  {
    \xeCJK_inter_class_toks:nnn { Boundary } {#1} { \xeCJK_Boundary_and_Default: }
    \xeCJK_app_inter_class_toks:nnn { CJK } {#1} { \CJKecglue }
  }
%    \end{macrocode}
%
% \begin{macro}[internal]{\xeCJK_Boundary_and_Default:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_Default:
  { \xeCJK_check_for_ecglue: }
\cs_new_protected_nopar:Npn \@@_check_for_xecglue:
  {
    \bool_if:nTF
      {
        \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven &&
        \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl
      }
      {
        \tex_unskip:D
        \bool_if:nTF
          {
            \xeCJK_if_last_node_p:n { CJK }       ||
            \xeCJK_if_last_node_p:n { CJK-space }
          }
          { \xeCJK_remove_node: \CJKecglue }
          { \xeCJK_space_glue: }
      }
      { \@@_check_for_ecglue: }
  }
\cs_new_protected_nopar:Npn \@@_check_for_ecglue:
  {
    \bool_if:nTF
      {
        \xeCJK_if_last_node_p:n { CJK }         ||
        \xeCJK_if_last_node_p:n { CJK-nobreak }
      }
      { \xeCJK_remove_node: \CJKecglue }
      {
        \xeCJK_if_last_node:nT { CJK-space }
          { \xeCJK_remove_node: \xeCJK_space_or_xecglue: }
      }
  }
\cs_new_eq:NN \xeCJK_check_for_ecglue: \@@_check_for_ecglue:
%    \end{macrocode}
% \end{macro}
%
% \hypertarget{def-bound}{}
%    \begin{macrocode}
\clist_map_inline:nn { Default , HalfRight }
  {
    \xeCJK_inter_class_toks:nnn {#1} { Boundary }
      {
        \int_gset_eq:NN \g_@@_spacefactor_int \tex_spacefactor:D
        \peek_meaning_remove:NTF \tex_italiccorrection:D
          {
            \tex_italiccorrection:D
            { \xeCJK_make_node:n { default } }
          }
          {
            \token_if_space:NTF \l_peek_token
              { { \xeCJK_make_node:n { default-space } } }
              { { \xeCJK_make_node:n { default } } }
          }
      }
    \xeCJK_pre_inter_class_toks:nnn {#1} { CJK } { \CJKecglue }
  }
%    \end{macrocode}
%
% \changes{v3.2.5}{2013/07/10}
% {修正 \texttt{CJK} 和 \texttt{NormalSpace} 字符类之间因为边界造成的间距不正确的问题。}
%
% \hypertarget{bound-ns}{}
%    \begin{macrocode}
\xeCJK_inter_class_toks:nnn { Boundary } { NormalSpace }
  { \xeCJK_Boundary_and_NormalSp: }
%    \end{macrocode}
%
% \begin{macro}[internal]{\xeCJK_Boundary_and_NormalSp:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_NormalSp:
  { \xeCJK_check_for_ecglue_normalsp: }
\cs_new_protected_nopar:Npn \@@_check_for_xecglue_normalsp:
  {
    \bool_if:nTF
      {
        \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven &&
        \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl
      }
      {
        \tex_unskip:D
        \bool_if:nTF
          {
            \xeCJK_if_last_node_p:n { CJK }       ||
            \xeCJK_if_last_node_p:n { CJK-space }
          }
          { \xeCJK_remove_node: \CJKecglue }
          { \xeCJK_space_glue: }
      }
      { \@@_check_for_ecglue_normalsp: }
  }
\cs_new_protected_nopar:Npn \@@_check_for_ecglue_normalsp:
  {
    \xeCJK_if_last_node:nT { CJK-space }
      { \xeCJK_remove_node: \xeCJK_space_or_xecglue: }
  }
\cs_new_eq:NN \xeCJK_check_for_ecglue_normalsp: \@@_check_for_ecglue_normalsp:
%    \end{macrocode}
% \end{macro}
%
% \hypertarget{ns-bound}{}
%    \begin{macrocode}
\xeCJK_inter_class_toks:nnn { NormalSpace } { Boundary }
  {
    \int_gset_eq:NN \g_@@_spacefactor_int \tex_spacefactor:D
    \peek_meaning_remove:NTF \tex_italiccorrection:D
      {
        \tex_italiccorrection:D
        { \xeCJK_make_node:n { normalspace } }
      }
      {
        \token_if_space:NTF \l_peek_token
          { { \xeCJK_make_node:n { default-space } } }
          { { \xeCJK_make_node:n { normalspace } } }
      }
  }
%    \end{macrocode}
%
% \hypertarget{bound-cjk}{}
%    \begin{macrocode}
\xeCJK_inter_class_toks:nnn { Boundary } { CJK }
  {
    \xeCJK_check_for_glue:
    \xeCJK_class_group_begin:
    \xeCJK_clear_Boundary_and_CJK_toks:
    \xeCJK_select_font:
    \CJKsymbol
  }
%    \end{macrocode}
%
% \begin{macro}[internal]{\xeCJK_check_for_glue:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_check_for_glue:
  {
    \bool_if:nTF
      { \xeCJK_if_last_node_p:n { CJK } || \xeCJK_if_last_node_p:n { CJK-space } }
      { \xeCJK_remove_node: \CJKglue }
      {
        \xeCJK_if_last_node:nTF { CJK-nobreak }
          { \xeCJK_remove_node: \xeCJK_no_break: \CJKglue }
          {
            \bool_if:nTF
              {
                \xeCJK_if_last_node_p:n { default }              ||
                \int_compare_p:nNn \etex_lastnodetype:D = \c_ten
              }
              { \xeCJK_remove_node: \CJKecglue }
              { \xeCJK_check_for_xglue: }
          }
      }
  }
\cs_new_eq:NN \xeCJK_check_for_xglue: \prg_do_nothing:
\cs_new_protected_nopar:Npn \@@_check_for_xglue:
  {
    \bool_if:nT
      {
        \int_compare_p:nNn \etex_lastnodetype:D = \c_eleven &&
        ( \skip_if_eq_p:nn \tex_lastskip:D \c_xeCJK_space_skip_tl ||
          \skip_if_eq_p:nn \tex_lastskip:D \l_@@_ecglue_skip )
      }
      {
        \tex_unskip:D
        \bool_if:nTF
          {
            \xeCJK_if_last_node_p:n { default-space }        ||
            \int_compare_p:nNn \etex_lastnodetype:D = \c_ten ||
            \xeCJK_if_last_node_p:n { default }
          }
          { \xeCJK_remove_node: \CJKecglue }
          {
            \bool_if:nTF
              {
                \xeCJK_if_last_node_p:n { CJK } ||
                \xeCJK_if_last_node_p:n { CJK-space }
              }
              {
                \xeCJK_remove_node:
                \bool_if:NTF \l_@@_reserve_space_bool
                  { \xeCJK_space_glue: }
                  { \CJKglue }
              }
              { \xeCJK_space_glue: }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF,internal]{\xeCJK_if_last_node:n}
%    \begin{macrocode}
 \prg_new_conditional:Npnn \xeCJK_if_last_node:n #1 { p , T , F , TF }
  {
    \if_dim:w \use:c { c_@@_#1_node_dim } = \tex_lastkern:D
      \prg_return_true: \else: \prg_return_false: \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.1.0}{2012/11/14}{删除多余的 \texttt{default-itcorr} 结点。}
% \changes{v3.2.4}{2013/07/03}{尽量移除用作判断标志的 \tn{kern}。}
%
% \begin{macro}[internal]{\xeCJK_declare_node:n,\xeCJK_make_node:n}
% \changes{v3.2.14}{2014/11/01}{保持 \tn{spacefactor}。}
% 用于判断插入的各种 |kern|。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_declare_node:n #1
  {
    \int_gincr:N \g_@@_node_int
    \dim_if_exist:cTF { c_@@_#1_node_dim }
      { \dim_gset:cn } { \dim_const:cn }
      { c_@@_#1_node_dim } { \g_@@_node_int sp }
  }
\int_new:N \g_@@_node_int
\int_gset_eq:NN \g_@@_node_int \c_ten
\cs_new_protected_nopar:Npn \xeCJK_make_node:n #1
  {
    \exp_after:wN \@@_make_node:N
    \cs:w c_@@_#1_node_dim \exp_after:wN \cs_end:
    \exp_after:wN \tex_spacefactor:D \int_use:N \tex_spacefactor:D \exp_stop_f:
  }
\cs_new_protected_nopar:Npn \@@_make_node:N #1
  {
    \tex_kern:D - #1
    \tex_kern:D   #1
  }
\cs_new_protected_nopar:Npn \xeCJK_remove_node:
  { \tex_unkern:D \tex_unkern:D }
\xeCJK_declare_node:n { CJK }
\xeCJK_declare_node:n { CJK-space }
\xeCJK_declare_node:n { default }
\xeCJK_declare_node:n { default-space }
\xeCJK_declare_node:n { CJK-nobreak }
\xeCJK_declare_node:n { normalspace }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{CJKglue}
% CJK 文字之间插入的 |glue|。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    CJKglue .code:n =
      {
        \cs_set_protected_nopar:Npn \CJKglue {#1}
        \xeCJK_glue_to_skip:nN {#1} \l_@@_ccglue_skip
      }
  }
\skip_new:N \l_@@_ccglue_skip
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.16}{2014/12/16}{整理 \texttt{xCJKecglue} 的部分代码。}
%
% \begin{macro}{CJKecglue,xCJKecglue}
% CJK 与西文和数学行内数学公式之间自动添加的空白。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    CJKecglue            .code:n =
      {
        \cs_set_protected_nopar:Npn \CJKecglue {#1}
        \xeCJK_glue_to_skip:nN {#1} \l_@@_ecglue_skip
      } ,
    xCJKecglue .choice: ,
    xCJKecglue / true    .code:n =
      {
        \bool_set_true:N  \l_@@_xecglue_bool
        \cs_set_eq:NN \xeCJK_space_or_xecglue: \CJKecglue
        \cs_set_eq:NN \xeCJK_check_for_xglue: \@@_check_for_xglue:
        \cs_set_eq:NN \xeCJK_check_for_ecglue: \@@_check_for_xecglue:
        \cs_set_eq:NN
          \xeCJK_check_for_ecglue_normalsp:
          \@@_check_for_xecglue_normalsp:
      } ,
    xCJKecglue / false   .code:n =
      {
        \bool_set_false:N \l_@@_xecglue_bool
        \cs_set_eq:NN \xeCJK_space_or_xecglue: \xeCJK_space_glue:
        \xeCJK_cs_clear:N \xeCJK_check_for_xglue:
        \cs_set_eq:NN \xeCJK_check_for_ecglue: \@@_check_for_ecglue:
        \cs_set_eq:NN
          \xeCJK_check_for_ecglue_normalsp:
          \@@_check_for_ecglue_normalsp:
      } ,
    xCJKecglue / unknown .code:n =
      {
        \bool_set_true:N  \l_@@_xecglue_bool
        \cs_set_protected_nopar:Npn \CJKecglue {#1}
        \xeCJK_glue_to_skip:nN {#1} \l_@@_ecglue_skip
        \cs_set_eq:NN \xeCJK_space_or_xecglue: \CJKecglue
        \cs_set_eq:NN \xeCJK_check_for_xglue: \@@_check_for_xglue:
      } ,
    xCJKecglue        .default:n = { true }
  }
\cs_new_eq:NN \xeCJK_space_glue: \c_space_tl
\skip_new:N \l_@@_ecglue_skip
\bool_new:N \l_@@_xecglue_bool
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{CJKspace}
% 是否保留 CJK 文字间的空白，默认不保留。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    CJKspace .bool_set:N = \l_@@_reserve_space_bool ,
    space        .meta:n = { CJKspace = true  } ,
    nospace      .meta:n = { CJKspace = false }
  }
%    \end{macrocode}
% \end{macro}
%
% \hypertarget{cjk-bound}{}
%    \begin{macrocode}
\xeCJK_inter_class_toks:nnn { CJK } { Boundary } { \xeCJK_CJK_and_Boundary:w }
%    \end{macrocode}
%
% \begin{macro}[internal]{\xeCJK_CJK_and_Boundary:w}
% \changes{v3.2.6}{2013/08/05}{更好的处理边界是 \tn{relax} 的情况。}
% 当边界是 \tn{relax} 的时候，它可能是由 |\csname ...\endcsname| 的形式产生的，
% 这样就可能出现问题\footnote{参见 \url{http://bbs.ctex.org/forum.php?mod=viewthread&tid=71563}。}。
% 原来是都在未定义控制序列前都加上 \cs{exp_not:N}，现在是采用分组结束后手工恢复的方式。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_CJK_and_Boundary:w
  {
    \xeCJK_peek_catcode_ignore_spaces:NTF \c_math_toggle_token
      {
        \bool_if:NTF \l_@@_peek_ignore_spaces_bool
          { \xeCJK_class_group_end: \xeCJK_space_or_xecglue: }
          { \xeCJK_class_group_end: \CJKecglue }
      }
      {
        \bool_if:NTF \l_@@_peek_ignore_spaces_bool
          {
            \bool_if:nTF
              {
                \token_if_macro_p:N \l_peek_token ||
                ( \l_@@_reserve_space_bool && \token_if_letter_p:N \l_peek_token )
              }
              {
                \xeCJK_class_group_end: { \xeCJK_make_node:n { CJK-space } }
                \xeCJK_space_or_xecglue:
              }
              { \xeCJK_class_group_end: { \xeCJK_make_node:n { CJK-space } } }
          }
          {
            \token_if_eq_meaning:NNTF \l_peek_token \scan_stop:
              { \@@_CJK_and_Boundary_relax:N }
              { \@@_CJK_and_Boundary_aux: }
          }
      }
  }
\cs_new_protected_nopar:Npn \@@_CJK_and_Boundary_aux:
  { \xeCJK_class_group_end: { \xeCJK_make_node:n { CJK } } }
\cs_new_protected:Npn \@@_CJK_and_Boundary_relax:N #1
  {
    \@@_CJK_and_Boundary_aux:
    \token_if_eq_meaning:NNTF #1 \scan_stop:
      {#1} { \cs_set_eq:NN #1 \scan_stop: #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_ignore_spaces:w}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_ignore_spaces:w
  {
    \xeCJK_peek_catcode_ignore_spaces:NTF \c_math_toggle_token
      {
        \bool_if:NTF \l_@@_peek_ignore_spaces_bool
          { \xeCJK_space_or_xecglue: } { \CJKecglue }
      }
      {
        \bool_if:NT \l_@@_peek_ignore_spaces_bool
          {
            \xeCJK_if_last_node:nT { CJK }
              { \xeCJK_remove_node: { \xeCJK_make_node:n { CJK-space } } }
            \bool_if:nT
              {
                \token_if_macro_p:N \l_peek_token ||
                ( \l_@@_reserve_space_bool && \token_if_letter_p:N \l_peek_token )
              }
              { \xeCJK_space_or_xecglue: }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \hypertarget{cjk-cjk}{}
%    \begin{macrocode}
\xeCJK_inter_class_toks:nnn { CJK } { CJK } { \xeCJK_CJK_and_CJK:N }
%    \end{macrocode}
%
% \begin{macro}[internal]{\xeCJK_CJK_and_CJK:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_CJK_and_CJK:N #1 { \CJKglue \CJKsymbol {#1} }
%    \end{macrocode}
% \end{macro}
%
% \hypertarget{fl-fr-others}{}
%    \begin{macrocode}
\xeCJK_inter_class_toks:nnn { FullLeft }  { CJK }
  { \xeCJK_FullLeft_and_CJK: \CJKsymbol }
\xeCJK_inter_class_toks:nnn { FullRight } { CJK }
  { \xeCJK_FullRight_and_CJK: \CJKsymbol }
\seq_map_inline:Nn \g_@@_non_CJK_class_seq
  {
    \clist_map_inline:nn { FullLeft , FullRight }
      {
        \xeCJK_inter_class_toks:nnx {#1} {##1}
          { \exp_not:c { xeCJK_Default_and_##1:nN } {#1} }
        \xeCJK_inter_class_toks:nnc {##1} {#1} { xeCJK_##1_and_Default: }
      }
  }
%    \end{macrocode}
%
% \hypertarget{bound-fl-fr}{}
%    \begin{macrocode}
\xeCJK_inter_class_toks:nnn { Boundary } { FullLeft }
  { \xeCJK_Boundary_and_FullLeft:N  }
\xeCJK_inter_class_toks:nnn { Boundary } { FullRight }
  { \xeCJK_Boundary_and_FullRight:N  }
%    \end{macrocode}
%
% \begin{macro}[internal]{\xeCJK_FullRight_and_Boundary:}
% \hypertarget{fl-fr-bound}{}
%    \begin{macrocode}
\xeCJK_app_inter_class_toks:nnn { FullLeft } { Boundary } { \tex_ignorespaces:D }
\xeCJK_inter_class_toks:nnn { FullRight } { Boundary }
  { \xeCJK_FullRight_and_Boundary: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_FullRight_and_Boundary:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_Boundary:
  { \xeCJK_FullRight_and_Default: \tex_ignorespaces:D }
%    \end{macrocode}
% \end{macro}
%
% \hypertarget{cjk-fl-fr}{}
%    \begin{macrocode}
\clist_map_inline:nn { CJK , FullLeft , FullRight }
  {
    \clist_map_inline:nn { FullLeft , FullRight }
      { \xeCJK_inter_class_toks:nnc {#1} {##1} { xeCJK_#1_and_##1:N } }
  }
%    \end{macrocode}
%
% \begin{macro}[internal]{\@@_punct_bound_rule:NN}
% 用于抹去标点符号的全部左/右空白。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_punct_bound_rule:NN #1#2
  {
    \tex_vrule:D
      width - \@@_use_punct_dim:nnn { bound } {#1} {#2}
      depth  \c_zero_dim
      height \c_zero_dim \scan_stop:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_punct_rule:NN}
% 用于减少标点符号的左/右空白。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_punct_rule:NN #1#2
  {
    \tex_vrule:D
      width  \@@_use_punct_dim:nnn { rule } {#1} {#2}
      depth  \c_zero_dim
      height \c_zero_dim \scan_stop:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_punct_offset:NN}
% 经过以上 \tn{vrule} 处理后，标点输出边界与实际边界的距离。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_punct_offset:NN #1#2
  { \@@_punct_kern:n { - \@@_use_punct_dim:nnn { offset } {#1} {#2} } }
\cs_new_protected_nopar:Npn \@@_punct_kern:n #1
  {
    \dim_compare:nNnF {#1} = \c_zero_dim
      { \tex_kern:D #1 \exp_stop_f: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_punct_glue:NN}
% \changes{v3.2.7}{2013/08/23}
% {标点符号左/右空白的伸展值不超过原始边界，收缩值不小于另一侧边界。}
% 根据所选的标点处理方式在标点符号左/右增加的空白。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_punct_glue:NN #1#2
  { \@@_punct_hskip:n { \@@_punct_skip:nn {#1} {#2} } }
\cs_new_eq:NN \@@_punct_hskip:n \skip_horizontal:n
\cs_new_protected_nopar:Npn \@@_punct_rigid_skip:nn #1#2
  { \@@_use_punct_dim:nnn { glue } {#1} {#2} }
\cs_new_protected_nopar:Npn \@@_punct_rubber_skip:nn #1#2
  {
    \@@_use_punct_dim:nnn { glue } {#1} {#2}
      plus  \@@_use_punct_dim:nnn { plus } {#1} {#2}
      minus \@@_use_punct_dim:nnn { minus } {#1} {#2}
  }
\cs_new_eq:NN \@@_punct_skip:nn \@@_punct_rubber_skip:nn
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_punct_kern:NN}
% 相邻两个标点之间的间距。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_punct_kern:NN #1#2
  { \tex_kern:D \@@_use_punct_dim:nnn { kern } {#1} {#2} \exp_stop_f: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal,var]{\g_@@_last_punct_tl}
% 用于记录当前的标点符号。
%    \begin{macrocode}
\tl_new:N \g_@@_last_punct_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_FullLeft_and_CJK:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_CJK:
  {
    \@@_punct_if_middle:NTF \g_@@_last_punct_tl
      {
        \@@_punct_bound_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
        \xeCJK_no_break:
        \@@_punct_glue:NN \c_@@_left_tl  \g_@@_last_punct_tl
      }
      { \xeCJK_no_break: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_FullLeft_and_Default:}
% \changes{v3.2.0}{2013/05/20}{修正 \pkg{xeCJK} 使西文在部分情况下无法断词的问题。}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_Default:
  {
    \@@_punct_if_middle:NTF \g_@@_last_punct_tl
      {
        \@@_punct_bound_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
        \xeCJK_class_group_end: \xeCJK_no_break:
        \@@_punct_glue:NN \c_@@_left_tl  \g_@@_last_punct_tl
      }
      { \xeCJK_class_group_end: \xeCJK_no_break: \@@_zero_glue: }
  }
\cs_new_protected_nopar:Npn \@@_zero_glue:
  { \skip_horizontal:N \c_zero_skip }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_FullRight_and_CJK:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_CJK:
  {
    \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
    \@@_punct_offset:NN \c_@@_right_tl \g_@@_last_punct_tl
    \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
    \CJKglue
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_FullRight_and_Default:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_Default:
  {
    \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
    \xeCJK_class_group_end:
    \@@_punct_offset:NN \c_@@_right_tl \g_@@_last_punct_tl
    \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_Default_and_FullLeft:nN}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_Default_and_FullLeft:nN #1#2
  {
    \xeCJK_get_punct_bounds:NN \c_@@_left_tl {#2}
    \@@_Default_and_FullLeft_glue:N {#2}
    \xeCJK_class_group_begin:
    \xeCJK_select_font:
    \xeCJK_clear_inter_class_toks:nn {#1} { FullLeft }
    \xeCJK_clear_Boundary_and_CJK_toks:
    \tl_gset:Nx \g_@@_last_punct_tl {#2}
    \@@_punct_rule:NN \c_@@_left_tl {#2}
    \CJKpunctsymbol {#2}
  }
\cs_new_protected_nopar:Npn \@@_Default_and_FullLeft_glue:N #1
  {
    \@@_punct_glue:NN \c_@@_left_tl {#1}
    \@@_punct_offset:NN \c_@@_left_tl {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_CJK_and_FullLeft:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_CJK_and_FullLeft:N #1
  {
    \xeCJK_get_punct_bounds:NN \c_@@_left_tl {#1}
    \@@_CJK_and_FullLeft_glue:N {#1}
    \tl_gset:Nx \g_@@_last_punct_tl {#1}
    \@@_punct_rule:NN \c_@@_left_tl {#1}
    \CJKpunctsymbol {#1}
  }
\cs_new_protected_nopar:Npn \@@_CJK_and_FullLeft_glue:N #1
  {
    \CJKglue
    \@@_punct_glue:NN \c_@@_left_tl {#1}
    \@@_punct_offset:NN \c_@@_left_tl {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_Boundary_and_FullLeft:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_FullLeft:N #1
  {
    \xeCJK_get_punct_bounds:NN \c_@@_left_tl {#1}
    \@@_Boundary_and_FullLeft_glue:N {#1}
    \@@_punct_offset:NN \c_@@_left_tl {#1}
    \xeCJK_class_group_begin:
    \xeCJK_select_font:
    \xeCJK_clear_Boundary_and_CJK_toks:
    \tl_gset:Nx \g_@@_last_punct_tl {#1}
    \@@_punct_rule:NN \c_@@_left_tl {#1}
    \CJKpunctsymbol {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_Boundary_and_FullLeft_glue:N}
% \changes{v3.2.0}{2013/05/22}{当全角左标点前面是 \texttt{hlist}、\texttt{none}、
% \texttt{glue} 和 \texttt{penalty} 等节点时，压缩其左空白。}
% \changes{v3.2.4}{2013/07/03}{细化边界与全角左标点之间是否压缩空白的判断。}
% \changes{v3.2.5}{2013/07/13}{细化全角左标点是否位于段首的判断。}
% \changes{v3.2.5}{2013/07/13}{增加对 \pkg{enumitem} 宏包修改的 \tn{item} 的判断。}
% \cs{etex_lastnodetype:D} 为 $1$ 表示 hlist node，在这里用来判断是否位于段首。基于
% 正常情况下，\TeX 会在段落开头插入宽度为 \tn{parindent} 的水平盒子用于缩进。
% $-1$ 表示 empty list，常出现在盒子的起始位置，在段落前使用 \tn{noindent} 就
% 是这种情况。$11$ 表示 glue node，这里判断的目的是当全角左标点出现在 \LaTeX 表格
% 的非 \texttt{p} 列行首时，能够对齐到单元格的边界。判断基于标准 \LaTeX 表格的
% 列格式（\tn{@tabclassz}）定义中，在 \texttt{l} 列和 \texttt{r} 列前为了防止
% \tn{tabcolsep} 被无意 \tn{unskip} 掉，都加了 |\hskip1sp|，而 \texttt{c} 列前
% 则有 \tn{hfil}。$13$ 表示 penalty node，这里判断的目的是全角左标点出现在 \LaTeX
% 列表环境的 \tn{item} 后面时，能对齐到边界。判断基于 \tn{item} 的内部定义
% \tn{@item} 对 \tn{everypar} 进行了修改，在这里起到影响作用的是
% |\box\@labels \penalty\z@|。\package{enumitem} 宏包修改了 \env{description}
% 环境中使用的 \tn{item}（\tn{enit@postlabel@i}），在这里起到影响作用的是
% |\penalty\z@ \hskip\labelsep|。以上判断都比较粗略，暂时也没有想起更好的办法。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_Boundary_and_FullLeft_glue:N #1
  {
    \int_case:nnTF { \etex_lastnodetype:D }
      {
        { \c_one       }
        {
          \box_set_to_last:N \l_@@_tmp_box
          \bool_if:nTF
            {
              \int_compare_p:nNn \etex_lastnodetype:D = \c_minus_one &&
              \dim_compare_p:nNn { \box_wd:N \l_@@_tmp_box } = \tex_parindent:D
            }
            { \box_use_clear:N \l_@@_tmp_box \use_none:n }
            { \box_use_clear:N \l_@@_tmp_box \use:n }
        }
        { \c_minus_one } { \@@_zero_glue: \use_none:n }
        { \c_eleven    }
        {
          \bool_if:nTF
            {
              ! ( \skip_if_finite_p:n { \tex_lastskip:D } ) ||
              \skip_if_eq_p:nn { \tex_lastskip:D } { 1 sp }
            }
            { \@@_zero_glue: \use_none:n }
            {
              \skip_if_eq:nnTF { \tex_lastskip:D } { \labelsep }
                {
                  \tex_unskip:D
                  \bool_if:nTF
                    {
                      \int_compare_p:nNn \etex_lastnodetype:D = \c_thirteen &&
                      \int_compare_p:nNn \tex_lastpenalty:D = \c_zero
                    }
                    { \skip_horizontal:n { \labelsep } \use_none:n }
                    { \skip_horizontal:n { \labelsep } \use:n }
                }
                { \use:n }
            }
        }
        { \c_thirteen  }
        {
          \int_compare:nNnTF \tex_lastpenalty:D = \c_zero
            {
              \tex_unpenalty:D
              \int_compare:nNnTF \etex_lastnodetype:D = \c_one
                { \tex_penalty:D \c_zero \use_none:n }
                { \tex_penalty:D \c_zero \use:n }
            }
            { \use:n }
        }
      }
      { { \@@_punct_glue:NN \c_@@_left_tl {#1} } }
      { \@@_punct_glue:NN \c_@@_left_tl {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_Default_and_FullRight:nN}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_Default_and_FullRight:nN #1#2
  {
    \xeCJK_get_punct_bounds:NN \c_@@_right_tl {#2}
    \@@_Default_and_FullRight_glue:N {#2}
    \xeCJK_class_group_begin:
    \xeCJK_select_font:
    \xeCJK_clear_inter_class_toks:nn {#1} { FullRight }
    \xeCJK_clear_Boundary_and_CJK_toks:
    \tl_gset:Nx \g_@@_last_punct_tl {#2}
    \xeCJK_FullRight_symbol:N {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_Boundary_and_FullRight:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_Boundary_and_FullRight:N #1
  {
    \xeCJK_get_punct_bounds:NN \c_@@_right_tl {#1}
    \@@_Default_and_FullRight_glue:N {#1}
    \xeCJK_class_group_begin:
    \xeCJK_select_font:
    \xeCJK_clear_Boundary_and_CJK_toks:
    \tl_gset:Nx \g_@@_last_punct_tl {#1}
    \xeCJK_FullRight_symbol:N {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_CJK_and_FullRight:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_CJK_and_FullRight:N #1
  {
    \xeCJK_get_punct_bounds:NN \c_@@_right_tl {#1}
    \@@_CJK_and_FullRight_glue:N {#1}
    \tl_gset:Nx \g_@@_last_punct_tl {#1}
    \xeCJK_FullRight_symbol:N {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
% {\@@_CJK_and_FullRight_glue:N,\@@_Default_and_FullRight_glue:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_CJK_and_FullRight_glue:N #1
  {
    \@@_punct_if_long:NTF {#1}
      { \CJKglue }
      {
        \@@_punct_if_middle:NTF {#1}
          {
            \xeCJK_no_break:
            \@@_punct_glue:NN \c_@@_right_tl {#1}
            \@@_punct_bound_rule:NN \c_@@_left_tl {#1}
          }
          { \xeCJK_no_break: }
      }
  }
\cs_new_eq:NN \@@_Default_and_FullRight_glue:N \@@_CJK_and_FullRight_glue:N
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_FullLeft_and_FullLeft:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_FullLeft:N #1
  {
    \xeCJK_no_break:
    \xeCJK_get_punct_bounds:NN \c_@@_left_tl {#1}
    \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl {#1}
    \@@_punct_kern:NN \g_@@_last_punct_tl {#1}
    \tl_gset:Nx \g_@@_last_punct_tl {#1}
    \CJKpunctsymbol {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_FullLeft_and_FullRight:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_FullLeft_and_FullRight:N #1
  {
    \xeCJK_no_break:
    \xeCJK_get_punct_bounds:NN \c_@@_right_tl {#1}
    \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl {#1}
    \@@_punct_kern:NN \g_@@_last_punct_tl {#1}
    \tl_gset:Nx \g_@@_last_punct_tl {#1}
    \xeCJK_no_break:
    \xeCJK_FullRight_symbol:N {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_FullRight_and_FullLeft:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullLeft:N #1
  {
    \xeCJK_get_punct_bounds:NN \c_@@_left_tl {#1}
    \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl {#1}
    \xeCJK_punct_kern:NN \g_@@_last_punct_tl {#1}
    \tl_gset:Nx \g_@@_last_punct_tl {#1}
    \CJKpunctsymbol {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_punct_nobreak_kern:NN}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_punct_nobreak_kern:NN #1#2
  {
    \@@_punct_kern:NN #1#2
    \xeCJK_no_break:
  }
\cs_new_eq:NN \xeCJK_punct_kern:NN \@@_punct_nobreak_kern:NN
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.4}{2013/07/06}
% {使用 \texttt{AllowBreakBetweenPuncts} 时，相应标点符号仍能与边界对齐。}
% \changes{v3.2.7}{2013/08/23}
% {处理 \texttt{AllowBreakBetweenPuncts} 与 \pkg{xeCJKfntef} 的兼容问题。}
%
% \begin{macro}[internal]{\@@_punct_breakable_kern:NN}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_punct_breakable_kern:NN #1#2
  {
    \@@_punct_rule:NN \c_@@_right_tl #1
    \@@_punct_breakable_kern:n
      { \@@_use_punct_dim:nnn { break_kern } {#1} {#2} }
    \@@_punct_rule:NN \c_@@_left_tl #2
  }
\cs_new_eq:NN \@@_punct_breakable_kern:n \skip_horizontal:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_FullRight_and_FullRight:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_FullRight_and_FullRight:N #1
  {
    \xeCJK_get_punct_bounds:NN \c_@@_right_tl {#1}
    \xeCJK_get_punct_kerning:oN \g_@@_last_punct_tl {#1}
    \@@_punct_kern:NN \g_@@_last_punct_tl {#1}
    \tl_gset:Nx \g_@@_last_punct_tl {#1}
    \xeCJK_no_break:
    \xeCJK_FullRight_symbol:N {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{全角右标点后的断行}
%
% \begin{macro}{CheckFullRight}
% \changes{v3.1.1}{2012/12/02}{处理全角右标点之后的断行问题。}
% 选项设置。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    CheckFullRight .choice: ,
    CheckFullRight / true  .code:n =
      {
        \cs_if_eq:NNF \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight:
          {
            \cs_set_eq:NN \@@_save_FullRight_check: \xeCJK_FullRight_and_Boundary:
            \cs_set_eq:NN \@@_save_FullRight_symbol:N \xeCJK_FullRight_symbol:N
            \cs_set_eq:NN \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight:
            \cs_set_eq:NN \xeCJK_FullRight_symbol:N \xeCJK_check_FullRight_symbol:Nw
          }
      } ,
    CheckFullRight / false .code:n =
      {
        \cs_if_eq:NNT \xeCJK_FullRight_and_Boundary: \xeCJK_check_FullRight:
          {
            \cs_set_eq:NN \xeCJK_FullRight_and_Boundary: \@@_save_FullRight_check:
            \cs_set_eq:NN \xeCJK_FullRight_symbol:N \@@_save_FullRight_symbol:N
          }
      } ,
    CheckFullRight      .default:n = { true }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_FullRight_symbol:N}
%    \begin{macrocode}
\cs_new_nopar:Npn \xeCJK_FullRight_symbol:N { \CJKpunctsymbol }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_check_FullRight:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_check_FullRight:
  {
    \xeCJK_get_punct_bounds:NN \c_@@_right_tl \g_@@_last_punct_tl
    \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
    \@@_punct_offset:NN \c_@@_right_tl \g_@@_last_punct_tl
    \group_align_safe_begin:
    \tl_case:NoTF \l_peek_token
      { \l_@@_no_break_cs_case_tl }
      { \group_align_safe_end: \xeCJK_no_break: }
      { \group_align_safe_end: }
    \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
    \xeCJK_class_group_end:
  }
\cs_generate_variant:Nn \tl_case:NnTF { No }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_check_FullRight_symbol:Nw}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_check_FullRight_symbol:Nw #1
  { \xeCJK_peek_after_ignore_spaces:nw { \@@_save_FullRight_symbol:N {#1} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_cs_case_keys_define:nNNnn}
%    \begin{macrocode}
\cs_new_protected:Npn \xeCJK_cs_case_keys_define:nNNnn #1#2#3#4#5
  {
    \tl_new:N #2
    \seq_new:N #3
    \keys_define:nn { xeCJK / options }
      {
        #1  .code:n =
          {
            \seq_set_split:Nnn #3 { } {##1}
            \@@_update_cs_case_tl:NNnn #2#3 {#4} {#5}
          } ,
        #1+ .code:n =
          {
            \tl_map_inline:nn {##1}
              { \seq_if_in:NnF #3 {####1} { \seq_put_right:Nn #3 {####1} } }
            \@@_update_cs_case_tl:NNnn #2#3 {#4} {#5}
          } ,
        #1- .code:n =
          {
            \tl_map_inline:nn {##1} { \seq_remove_all:Nn #3 {####1} }
            \@@_update_cs_case_tl:NNnn #2#3 {#4} {#5}
          }
      }
  }
\cs_new_protected:Npn \@@_update_cs_case_tl:NNnn #1#2#3#4
  {
    \tl_clear:N #1
    \seq_map_inline:Nn #2 { \tl_put_right:Nn #1 { {##1} {#3} } }
    #4
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{NoBreakCS}
% 设置不能在全角右标点之后断行的控制序列。
%    \begin{macrocode}
\xeCJK_cs_case_keys_define:nNNnn { NoBreakCS }
  \l_@@_no_break_cs_case_tl \l_@@_no_break_cs_seq { } { }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKnobreak}
% \changes{v3.1.1}{2012/12/03}{增加 \tn{nobreak} 的 \pkg{xeCJK} 版本。}
% 为保险起见，我们在这里用了一个循环。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKnobreak { }
  {
    \bool_set_true:N \l_@@_tmp_bool
    \int_while_do:nNnn \etex_lastnodetype:D = \c_eleven
      {
        \bool_if:NTF \l_@@_tmp_bool
          {
            \bool_set_false:N \l_@@_tmp_bool
            \skip_set_eq:NN \l_@@_tmp_skip \tex_lastskip:D
          }
          { \skip_add:Nn \l_@@_tmp_skip \tex_lastskip:D }
        \tex_unskip:D
      }
    \xeCJK_no_break:
    \bool_if:NF \l_@@_tmp_bool { \skip_horizontal:N \l_@@_tmp_skip }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{段末孤字处理}
%
% \begin{macro}{CheckSingle}
% 孤字处理功能选项。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    CheckSingle .choice: ,
    CheckSingle / true  .code:n =
      {
        \cs_if_eq:NNF \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw
          {
            \cs_set_eq:NN \@@_check_single_save:N \xeCJK_CJK_and_CJK:N
            \cs_set_eq:NN \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw
          }
      } ,
    CheckSingle / false .code:n =
      {
        \cs_if_eq:NNT \xeCJK_CJK_and_CJK:N \xeCJK_check_single:Nw
          { \cs_set_eq:NN  \xeCJK_CJK_and_CJK:N \@@_check_single_save:N }
      } ,
    CheckSingle      .default:n = { true } ,
    CJKchecksingle      .meta:n = { CheckSingle = true }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_check_single:Nw}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_check_single:Nw #1
  {
    \peek_catcode:NTF \c_catcode_letter_token
      { \xeCJK_check_single:NNw #1 }
      {
        \group_align_safe_begin:
        \token_if_other:NTF \l_peek_token
          { \group_align_safe_end: \xeCJK_check_single:NNw #1 }
          {
            \group_align_safe_end:
            \bool_if:nTF
              {
                \str_if_eq_x_p:nn { \token_get_arg_spec:N \l_peek_token } { } &&
                \exp_args:No \tl_if_single_token_p:n \l_peek_token            &&
                ( \exp_after:wN \token_if_other_p:N  \l_peek_token ||
                  \exp_after:wN \token_if_letter_p:N \l_peek_token )
              }
              { \exp_after:wN \xeCJK_check_single:NNw \exp_after:wN #1 }
              { \@@_check_single_save:N #1 }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_check_single:NNw}
% \changes{v3.1.1}{2012/12/04}{改进定义，减少使用 \texttt{peek} 函数的次数。}
% \changes{v3.2.7}{2013/08/30}{与 \tn{CJKspace} 兼容。}
% 使用 \cs{group_align_safe_begin:} 和 \cs{group_align_safe_end:} 是为了防止在表格
% 里面报错。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_check_single:NNw #1#2
  {
    \xeCJK_peek_catcode_ignore_spaces:NTF \c_catcode_letter_token
      {
        \bool_if:NTF \l_@@_peek_ignore_spaces_bool
          {
            \bool_if:NTF \l_@@_reserve_space_bool
              { \@@_check_single_save:N #1 #2 ~ }
              { \@@_check_single_space:NN #1#2 }
          }
          { \@@_check_single_save:N #1 #2 }
      }
      {
        \group_align_safe_begin:
        \token_if_other:NTF \l_peek_token
          {
            \group_align_safe_end:
            \bool_if:NTF \l_@@_peek_ignore_spaces_bool
              { \@@_check_single_space:NN #1#2 }
              { \@@_check_single_save:N #1 #2 }
          }
          {
            \token_if_cs:NTF \l_peek_token
              {
                \group_align_safe_end:
                \bool_if:NTF \l_@@_peek_ignore_spaces_bool
                  { \xeCJK_check_single_cs:NNn #1#2 { ~ } }
                  { \xeCJK_check_single_cs:NNn #1#2 { } }
              }
              {
                \group_align_safe_end:
                \bool_if:nTF
                  {
                    \l_@@_plain_equation_bool &&
                    \token_if_math_toggle_p:N \l_peek_token
                  }
                  {
                    \bool_if:NTF \l_@@_peek_ignore_spaces_bool
                      { \xeCJK_check_single_equation:NNnNw #1 #2 { ~ } }
                      { \xeCJK_check_single_equation:NNnNw #1 #2 { } }
                  }
                  {
                    \bool_if:NTF \l_@@_peek_ignore_spaces_bool
                      { \@@_check_single_save:N #1 #2 ~ }
                      { \@@_check_single_save:N #1 #2 }
                  }
              }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_check_single_space:NN}
% \changes{v3.1.1}{2012/12/13}
% {\texttt{CheckSingle} 支持段末“汉字$+$汉字$+$空格$+$汉字/标点”的形式。}
% \changes{v3.1.2}{2012/12/27}
% {使用 \cs{xeCJK_if_CJK_class:NTF} 来代替 \cs{int_case:nnn} 判断是否是 CJK 字符类。}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_check_single_space:NN #1#2
  {
    \xeCJK_if_CJK_class:NTF #2
      {
        \xeCJK_if_CJK_class:NTF \l_peek_token
          { \@@_check_single_save:N #1 #2 }
          { \@@_check_single_save:N #1 #2 ~ }
      }
      { \@@_check_single_save:N #1 #2 ~ }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_check_single_equation:NNnNw}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_check_single_equation:NNnNw #1#2#3#4
  {
    \peek_catcode:NTF \c_math_toggle_token
      {
        \xeCJK_no_break: \@@_check_single_save:N #1
        \xeCJK_make_node:n { CJK-nobreak } #2 #4
      }
      { \@@_check_single_save:N #1 #2#3#4 }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.3}{2013/06/11}
% {解决 \texttt{CheckSingle} 选项与 \pkg{tablists} 宏包的冲突。}
% \changes{v3.2.4}{2013/06/26}
% {解决使用 \texttt{CheckSingle} 时，某些 \tn{CJKglue} 不能被正确加入的问题。}
%
% \begin{macro}[internal]{\xeCJK_check_single_cs:NNn}
% 在使用 \texttt{CheckSingle} 选项时，在 \package{tablists} 宏包定义的
% \env{tabenum} 环境中会出现下面的错误：
% \begin{verbatim}
%   ! Forbidden control sequence found while scanning use of \use_ii:nn.
%   <inserted text>
%                   \par
%    l.10 \item
% \end{verbatim}
% 原因在于 \env{tabenum} 实际上是一个 \TeX 对齐环境（\tn{halign}），\tn{par} 在
% 其中被重定义为 \tn{cr}。而在下面 \cs{tl_case:NnF} 的分支里有对 \tn{par} 的
% \tn{ifx} 判断。解决办法是将判断用 \cs{group_align_safe_begin:} 和
% \cs{group_align_safe_end:} 包起来。或者改用原语 \cs{tex_par:D} 作为判断条件。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_check_single_cs:NNn #1#2#3
  {
    \group_align_safe_begin:
    \tl_case:NoF \l_peek_token
      { \l_@@_check_single_cs_case_tl }
      { \group_align_safe_end: \use_iii:nnn }
      { \xeCJK_check_single_env:nnNn }
      {
        \xeCJK_no_break: \@@_check_single_save:N #1
        \xeCJK_make_node:n { CJK-nobreak } #2
      }
      { \@@_check_single_save:N #1 #2#3 }
  }
\tl_new:N \l_@@_check_single_cs_case_tl
\cs_generate_variant:Nn \tl_case:NnF { No }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_check_single_env:nnNn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_check_single_env:nnNn #1#2#3#4
  {
    \group_align_safe_begin:
    \str_case_x:noTF {#4}
      { \l_@@_inline_env_case_tl }
      { \group_align_safe_end: #2 }
      { \group_align_safe_end: #1 }
    #3 {#4}
  }
\cs_generate_variant:Nn \str_case_x:nnTF { no }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.1.1}{2012/12/04}{增加 \texttt{NewLineCS} 和 \texttt{EnvCS} 选项。}
%
% \begin{macro}{NewLineCS}
%    \begin{macrocode}
\xeCJK_cs_case_keys_define:nNNnn { NewLineCS }
  \l_@@_new_line_cs_case_tl \l_@@_new_line_cs_seq
  { \group_align_safe_end: \use_ii:nnn }
  {
    \tl_concat:NNN \l_@@_check_single_cs_case_tl
      \l_@@_new_line_cs_case_tl \l_@@_env_cs_case_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{EnvCS}
%    \begin{macrocode}
\xeCJK_cs_case_keys_define:nNNnn { EnvCS }
  \l_@@_env_cs_case_tl \l_@@_env_cs_seq
  { \group_align_safe_end: \use:n }
  {
    \tl_concat:NNN \l_@@_check_single_cs_case_tl
      \l_@@_new_line_cs_case_tl \l_@@_env_cs_case_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{InlineEnv}
% \changes{v3.1.1}{2012/12/05}{改变行内环境的设置方式，从而使用 \cs{str_case_x:nnn}
% 代替原来的 \cs{clist_if_in:NnTF} 来判断是否是行内环境。}
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    InlineEnv  .code:n =
      {
        \seq_set_from_clist:Nn \l_@@_inline_env_seq {#1}
        \@@_update_inline_env_case_tl:
      } ,
    InlineEnv+      .code:n =
      {
        \clist_map_inline:nn {#1}
          {
            \seq_if_in:NnF \l_@@_inline_env_seq {##1}
              { \seq_put_right:Nn \l_@@_inline_env_seq {##1} }
          }
        \@@_update_inline_env_case_tl:
      } ,
    InlineEnv-      .code:n =
      {
        \clist_map_inline:nn {#1}
          { \seq_remove_all:Nn \l_@@_inline_env_seq {##1} }
        \@@_update_inline_env_case_tl:
      }
  }
\seq_new:N \l_@@_inline_env_seq
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_update_inline_env_case_tl:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_update_inline_env_case_tl:
  {
    \tl_clear:N \l_@@_inline_env_case_tl
    \seq_map_inline:Nn \l_@@_inline_env_seq
      { \tl_put_right:Nn \l_@@_inline_env_case_tl { {##1} { } } }
  }
\tl_new:N \l_@@_inline_env_case_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{PlainEquation}
% \changes{v3.1.1}{2012/12/06}{增加 \texttt{PlainEquation} 选项。}
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  { PlainEquation .bool_set:N = \l_@@_plain_equation_bool }
%    \end{macrocode}
% \end{macro}
%
% \subsection{增加 CJK 子分区}
%
% \begin{macro}[internal]{\g_@@_CJK_sub_class_seq}
%    \begin{macrocode}
\seq_new:N \g_@@_CJK_sub_class_seq
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKDeclareSubCJKBlock}
% 声明 CJK 子区范围，|#1| 为自定义名称，|#2| 为子区的 |Unicode| 范围。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKDeclareSubCJKBlock
  { s > { \TrimSpaces } m > { \TrimSpaces } m }
  {
    \xeCJK_declare_sub_char_class:nxx { CJK } {#2} {#3}
    \IfBooleanT {#1} { \xeCJKResetPunctClass }
  }
\@onlypreamble \xeCJKDeclareSubCJKBlock
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKCancelSubCJKBlock,\xeCJKRestoreSubCJKBlock}
% 取消和恢复对 CJK 子区的声明。
%    \begin{macrocode}
\bool_new:N \l_@@_sub_cancel_bool
\NewDocumentCommand \xeCJKCancelSubCJKBlock { s m }
  {
    \bool_if:NF \l_@@_sub_cancel_bool
      {
        \bool_set_true:N \l_@@_sub_cancel_bool
        \@@_sub_restore_or_cancel:x {#2}
        \IfBooleanT {#1} { \xeCJKResetPunctClass }
      }
  }
\NewDocumentCommand \xeCJKRestoreSubCJKBlock { s m }
  {
    \bool_if:NT \l_@@_sub_cancel_bool
      {
        \bool_set_false:N \l_@@_sub_cancel_bool
        \@@_sub_restore_or_cancel:x {#2}
        \IfBooleanT {#1} { \xeCJKResetPunctClass }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_sub_restore_or_cancel:n}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_sub_restore_or_cancel:n #1
  {
    \clist_map_inline:nn {#1}
      {
        \int_if_exist:cTF { \@@_class_csname:n { CJK/##1 } }
          {
            \xeCJK_declare_char_class:nx
              { CJK \bool_if:NF \l_@@_sub_cancel_bool { /##1 } }
              { \tl_use:c { g_@@_CJK/##1_range_clist } }
          }
          { \@@_error:nx { SubBlock-undefined } {##1} }
      }
  }
\cs_generate_variant:Nn \@@_sub_restore_or_cancel:n { x }
\@@_msg_new:nn { SubBlock-undefined }
  {
    The~CJK~sub~block~`#1'~is~undefined.\\\\
    Try~to~use~\token_to_str:N \xeCJKDeclareSubCJKBlock \
    to~declare~it.
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_declare_sub_char_class:nnn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_declare_sub_char_class:nnn #1#2#3
  {
    \int_if_exist:cF { \@@_class_csname:n { #1/#2 } }
      {
        \xeCJK_new_class:n { #1/#2 }
        \@@_set_sub_class_toks:nn {#1} {#2}
        \xeCJK_new_sub_key:n {#2}
      }
    \xeCJK_declare_char_class:nn { #1/#2 } {#3}
  }
\cs_generate_variant:Nn \xeCJK_declare_sub_char_class:nnn { nxx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_set_sub_class_toks:nn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_set_sub_class_toks:nn #1#2
  {
    \seq_map_inline:Nn \g_@@_base_class_seq
      {
        \xeCJK_copy_inter_class_toks:nnnn { #1/#2 } {##1} {#1}  {##1}
        \xeCJK_copy_inter_class_toks:nnnn {##1} { #1/#2 } {##1} {#1}
        \str_if_eq:nnTF {##1} { CJK }
          {
            \xeCJK_pre_inter_class_toks:nnn {##1} { #1/#2 }
              { \@@_switch_font:nn {#1} {#2} }
          }
          {
            \xeCJK_replace_inter_class_toks:nnnn {##1} { #1/#2 }
              { \CJKsymbol }
              { \@@_switch_font:nn {#1} {#2} \CJKsymbol }
          }
      }
    \xeCJK_copy_inter_class_toks:nnnn { #1/#2 } { #1/#2 } {#1} {#1}
    \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
      {
        \xeCJK_copy_inter_class_toks:nnnn { #1/#2  } { #1/##1 } {#1} {#1}
        \xeCJK_copy_inter_class_toks:nnnn { #1/##1 } { #1/#2  } {#1} {#1}
        \xeCJK_pre_inter_class_toks:nnn { #1/#2 } { #1/##1 }
          { \@@_switch_font:nn {#2} {##1} }
        \xeCJK_pre_inter_class_toks:nnn { #1/##1 } { #1/#2 }
          { \@@_switch_font:nn {##1} {#2} }
      }
    \seq_gput_right:Nn \g_@@_CJK_sub_class_seq {#2}
    \@@_save_CJK_class:n { #1/#2 }
    \clist_map_inline:nn { CJK , FullLeft , FullRight , HangulJamo }
      {
        \xeCJK_pre_inter_class_toks:nnn { #1/#2 } {##1}
          { \@@_switch_font:nn {#2} {#1} }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{标点处理}
%
% \changes{v3.2.7}{2013/08/22}{实现自定义行首/尾标点符号宽度功能。}
%
% \tn{XeTeXglyphbouds} 可以得到一个字符的左右边距，用于标点压缩。如果它不可用，则
% 在文档中只能使用 |plain| 这一标点格式原样输出标点。
%    \begin{macrocode}
\cs_if_exist:NF \XeTeXglyphbounds
  {
    \@@_msg_new:nn { XeTeX-too-old }
      {
        \token_to_str:N \XeTeXglyphbounds \ is~not~defined.\\
        CJK~punctuation~kerning~will~not~be~available.\\\\
        You~have~to~update~XeTeX~to~the~version~0.9995.0~or~later.
      }
    \@@_error:n { XeTeX-too-old }
    \AtEndOfPackage
      {
        \keys_define:nn { xeCJK / options }
          {
            PunctStyle / unknown .code:n =
              { \@@_error:nx { punct-style-unknown } { \l_keys_value_tl } }
          }
        \seq_gclear:N \g_@@_punct_style_seq
        \keys_set:nn { xeCJK / options } { PunctStyle = plain }
      }
  }
%    \end{macrocode}
%
% \begin{macro}{\xeCJKsetwidth}
% 手动设置参数中的标点符号的宽度。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKsetwidth { s m m }
  {
    \IfBooleanTF {#1}
      {
        \tl_map_inline:xn {#2}
          { \tl_gset:cn { g_@@_punct_bound_width/##1/tl } {#3} }
      }
      {
        \tl_map_inline:xn {#2}
          { \tl_gset:cn { g_@@_punct_width/##1/tl } {#3} }
      }
  }
\@onlypreamble \xeCJKsetwidth
\cs_generate_variant:Nn \tl_map_inline:nn { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKsetkern}
% 手动设置相邻标点的距离。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKsetkern { m m m }
  { \tl_gset:cn { g_@@_punct/kern/#1/#2/tl } {#3} }
\@onlypreamble \xeCJKsetkern
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal,var]{\c_@@_left_tl,\c_@@_right_tl}
%    \begin{macrocode}
\tl_const:Nn \c_@@_left_tl  { left }
\tl_const:Nn \c_@@_right_tl { right }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.12}{2014/05/12}{新增 \texttt{RubberPunctSkip} 选项。}
%
% \begin{macro}
%  {AllowBreakBetweenPuncts,KaiMingPunct,LongPunct,
%   MiddlePunct,PunctWidth,PunctBoundWidth,RubberPunctSkip}
% 相关选项声明。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    AllowBreakBetweenPuncts .choice: ,
    AllowBreakBetweenPuncts / true  .code:n =
      {
        \bool_set_true:N \l_@@_punct_breakable_bool
        \cs_set_eq:NN \xeCJK_punct_kern:NN \@@_punct_breakable_kern:NN
      } ,
    AllowBreakBetweenPuncts / false .code:n =
      {
        \bool_set_false:N \l_@@_punct_breakable_bool
        \cs_set_eq:NN \xeCJK_punct_kern:NN \@@_punct_nobreak_kern:NN
      } ,
    AllowBreakBetweenPuncts      .default:n = { true } ,
    KaiMingPunct  .code:n = { \@@_set_special_punct:nn { mixed_width } {#1} } ,
    KaiMingPunct+ .code:n = { \@@_add_special_punct:nn { mixed_width } {#1} } ,
    KaiMingPunct- .code:n = { \@@_sub_special_punct:nn { mixed_width } {#1} } ,
    LongPunct     .code:n = { \@@_set_special_punct:nn { long } {#1} } ,
    LongPunct+    .code:n = { \@@_add_special_punct:nn { long } {#1} } ,
    LongPunct-    .code:n = { \@@_sub_special_punct:nn { long } {#1} } ,
    MiddlePunct   .code:n = { \@@_set_special_punct:nn { middle } {#1} } ,
    MiddlePunct+  .code:n = { \@@_add_special_punct:nn { middle } {#1} } ,
    MiddlePunct-  .code:n = { \@@_sub_special_punct:nn { middle } {#1} } ,
    PunctWidth      .tl_gset:N = \g_@@_punct_width_tl ,
    PunctBoundWidth .tl_gset:N = \g_@@_punct_bound_width_tl ,
    PunctWidth      .value_required: ,
    PunctBoundWidth .value_required: ,
    RubberPunctSkip .choice: ,
    RubberPunctSkip      .default:n = { true } ,
    RubberPunctSkip / true  .code:n =
      { \cs_set_eq:NN \@@_punct_skip:nn \@@_punct_rubber_skip:nn } ,
    RubberPunctSkip / false .code:n =
      { \cs_set_eq:NN \@@_punct_skip:nn \@@_punct_rigid_skip:nn }
  }
\bool_new:N \l_@@_punct_breakable_bool
%    \end{macrocode}
% \end{macro}
%
% 相关选项定义的辅助函数。
%    \begin{macrocode}
\clist_new:N \g_@@_special_punct_clist
\clist_gset:Nn \g_@@_special_punct_clist { mixed_width , long , middle }
\cs_new_nopar:Npn \@@_special_punct_seq:n #1 { g_@@_special_punct_#1_seq }
\cs_new_nopar:Npn \@@_special_punct_tl:nN #1#2 { g_@@_special_punct_#1_#2_tl }
\clist_map_inline:Nn \g_@@_special_punct_clist
  { \seq_new:c { \@@_special_punct_seq:n {#1} } }
\cs_new_protected_nopar:Npn \@@_set_special_punct:nn #1#2
  {
    \seq_map_inline:cn { \@@_special_punct_seq:n {#1} }
      { \cs_undefine:c { \@@_special_punct_tl:nN {#1} {##1} } }
    \seq_gclear:c { \@@_special_punct_seq:n {#1} }
    \tl_map_inline:xn {#2}
      {
        \tl_new:c { \@@_special_punct_tl:nN {#1} {##1} }
        \seq_gput_right:cn { \@@_special_punct_seq:n {#1} } {##1}
      }
  }
\cs_new_protected_nopar:Npn \@@_add_special_punct:nn #1#2
  {
    \tl_map_inline:xn {#2}
      {
        \seq_if_in:cnF { \@@_special_punct_seq:n {#1} } {##1}
          {
            \tl_new:c { \@@_special_punct_tl:nN {#1} {##1} }
            \seq_gput_right:cn { \@@_special_punct_seq:n {#1} } {##1}
          }
      }
  }
\cs_new_protected_nopar:Npn \@@_sub_special_punct:nn #1#2
  {
    \tl_map_inline:xn {#2}
      {
        \cs_undefine:c { \@@_special_punct_tl:nN {#1} {##1} }
        \seq_gremove_all:cn { \@@_special_punct_seq:n {#1} } {##1}
      }
  }
%    \end{macrocode}
%
% 判断一个标点符号是否为全角右标点和长标点符号。
%    \begin{macrocode}
\prg_new_conditional:Npnn \@@_punct_if_right:N #1 { p , T , F , TF }
  {
    \if_int_compare:w \xeCJK_token_value_class:N #1 = \xeCJK_class_num:n { FullRight }
      \prg_return_true: \else: \prg_return_false: \fi:
  }
\clist_map_inline:Nn \g_@@_special_punct_clist
  {
    \exp_args:Nc
    \prg_new_conditional:Npnn { @@_punct_if_#1:N } ##1 { p , T , F , TF }
      {
        \if_cs_exist:w \@@_special_punct_tl:nN {#1} {##1} \cs_end:
          \prg_return_true: \else: \prg_return_false: \fi:
      }
  }
%    \end{macrocode}
%
% 一些用于记录的辅助函数。
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_punct_dim_csname:nn #1#2
  { c__\l_xeCJK_current_font_tl/\l_xeCJK_punct_style_tl/#1/#2/tl }
\cs_new_nopar:Npn \@@_punct_dim_csname:nnn #1#2#3
  { c__\l_xeCJK_current_font_tl/\l_xeCJK_punct_style_tl/#1/#2/#3/tl }
\cs_new_nopar:Npn \@@_use_punct_dim:nn #1#2
  { \use:c { \@@_punct_dim_csname:nn {#1} {#2} } }
\cs_new_nopar:Npn \@@_use_punct_dim:nnn #1#2#3
  { \use:c { \@@_punct_dim_csname:nnn {#1} {#2} {#3} } }
\cs_new_protected_nopar:Npn \@@_save_punct_dim:nnn #1#2#3
  { \tl_const:cx { \@@_punct_dim_csname:nn {#1} {#2} } { \dim_eval:n {#3} } }
\cs_new_protected_nopar:Npn \@@_save_punct_dim:nnnn #1#2#3#4
  { \tl_const:cx { \@@_punct_dim_csname:nnn {#1} {#2} {#3} } { \dim_eval:n {#4} } }
%    \end{macrocode}
%
% \changes{v3.1.0}{2012/11/14}{使用 \pkg{xtemplate} 宏包的机制来组织标点符号的处理。}
%
% 定义标点处理模板。
%    \begin{macrocode}
\DeclareObjectType { xeCJK / punctuation } { \c_zero }
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareTemplateInterface { xeCJK / punctuation } { basic } { \c_zero }
  {
    enabled-global-setting  : boolean = true ,
    fixed-punct-width       : length  = \c_max_dim ,
    fixed-punct-ratio       : real    = \c_one_fp ,
    mixed-punct-width       : length  = \KeyValue { fixed-punct-width } ,
    mixed-punct-ratio       : real    = \KeyValue { fixed-punct-ratio } ,
    middle-punct-width      : length  = \KeyValue { fixed-punct-width } ,
    middle-punct-ratio      : real    = \KeyValue { fixed-punct-ratio } ,
    fixed-margin-width      : length  = \c_max_dim ,
    fixed-margin-ratio      : real    = \c_one_fp ,
    mixed-margin-width      : length  = \KeyValue { fixed-margin-width } ,
    mixed-margin-ratio      : real    = \KeyValue { fixed-margin-ratio } ,
    middle-margin-width     : length  = \KeyValue { fixed-margin-width } ,
    middle-margin-ratio     : real    = \KeyValue { fixed-margin-ratio } ,
    bound-punct-width       : length  = \c_max_dim ,
    bound-punct-ratio       : real    = \c_nan_fp ,
    bound-margin-width      : length  = \c_max_dim ,
    bound-margin-ratio      : real    = \c_zero_fp ,
    enabled-hanging         : boolean = false ,
    add-min-bound-to-margin : boolean = false ,
    optimize-margin         : boolean = false ,
    margin-minimum          : length  = \c_zero_dim ,
    enabled-kerning         : boolean = true ,
    min-bound-to-kerning    : boolean = false ,
    kerning-total-width     : length  = \c_max_dim ,
    kerning-total-ratio     : real    = 0.75 ,
    optimize-kerning        : boolean = false ,
    same-align-margin       : length  = \c_max_dim ,
    same-align-ratio        : real    = \c_nan_fp ,
    different-align-margin  : length  = \c_max_dim ,
    different-align-ratio   : real    = \c_nan_fp ,
    kerning-margin-width    : length  = \c_max_dim ,
    kerning-margin-ratio    : real    = \c_one_fp ,
    kerning-margin-minimum  : length  = \c_zero_dim
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareTemplateCode { xeCJK / punctuation } { basic } { \c_zero }
  {
    enabled-global-setting  = \l_@@_enabled_global_setting_bool ,
    fixed-punct-width       = \l_@@_fixed_punct_width_dim ,
    fixed-punct-ratio       = \l_@@_fixed_punct_ratio_fp ,
    mixed-punct-width       = \l_@@_mixed_punct_width_dim ,
    mixed-punct-ratio       = \l_@@_mixed_punct_ratio_fp ,
    middle-punct-width      = \l_@@_middle_punct_width_dim ,
    middle-punct-ratio      = \l_@@_middle_punct_ratio_fp ,
    fixed-margin-width      = \l_@@_fixed_margin_width_dim ,
    fixed-margin-ratio      = \l_@@_fixed_margin_ratio_fp ,
    mixed-margin-width      = \l_@@_mixed_margin_width_dim ,
    mixed-margin-ratio      = \l_@@_mixed_margin_ratio_fp ,
    middle-margin-width     = \l_@@_middle_margin_width_dim ,
    middle-margin-ratio     = \l_@@_middle_margin_ratio_fp ,
    bound-punct-width       = \l_@@_bound_punct_width_dim ,
    bound-punct-ratio       = \l_@@_bound_punct_ratio_fp ,
    bound-margin-width      = \l_@@_bound_margin_width_dim ,
    bound-margin-ratio      = \l_@@_bound_margin_ratio_fp ,
    enabled-hanging         = \l_@@_enabled_hanging_bool ,
    add-min-bound-to-margin = \l_@@_add_min_bound_to_margin_bool ,
    optimize-margin         = \l_@@_optimize_margin_bool ,
    margin-minimum          = \l_@@_margin_minimum_dim ,
    enabled-kerning         = \l_@@_enabled_kerning_bool ,
    min-bound-to-kerning    = \l_@@_min_bound_to_kerning_bool ,
    kerning-total-width     = \l_@@_kerning_total_width_dim ,
    kerning-total-ratio     = \l_@@_kerning_total_ratio_fp ,
    optimize-kerning        = \l_@@_optimize_kerning_bool ,
    same-align-margin       = \l_@@_same_align_margin_dim ,
    same-align-ratio        = \l_@@_same_align_ratio_fp ,
    different-align-margin  = \l_@@_different_align_margin_dim ,
    different-align-ratio   = \l_@@_different_align_ratio_fp ,
    kerning-margin-width    = \l_@@_kerning_margin_width_dim ,
    kerning-margin-ratio    = \l_@@_kerning_margin_ratio_fp ,
    kerning-margin-minimum  = \l_@@_kerning_margin_minimum_dim
  }
  { \AssignTemplateKeys }
%    \end{macrocode}
%
% \begin{macro}[internal]{\xeCJK_get_punct_bounds:NN}
% |#1| 为 \cs{c_@@_left_tl} 或 \cs{c_@@_right_tl}，|#2| 为标点符号。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_get_punct_bounds:NN #1#2
  {
    \tl_if_exist:cF { \@@_punct_dim_csname:nnn { glue } {#1} {#2} }
      {
        \tl_if_eq:NNTF \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl
          {
            \@@_save_punct_dim:nnnn { rule }   {#1} {#2} { \c_zero_dim }
            \@@_save_punct_dim:nnnn { glue }   {#1} {#2} { \c_zero_dim }
            \@@_save_punct_dim:nnnn { plus }   {#1} {#2} { \c_zero_dim }
            \@@_save_punct_dim:nnnn { minus }  {#1} {#2} { \c_zero_dim }
            \@@_save_punct_dim:nnnn { offset } {#1} {#2} { \c_zero_dim }
            \@@_save_punct_dim:nnnn { bound } \c_@@_left_tl  {#2} { \c_zero_dim }
            \@@_save_punct_dim:nnnn { bound } \c_@@_right_tl {#2} { \c_zero_dim }
          }
          {
            { \xeCJK_select_font: \xeCJK_calc_punct_dimen:f {#2} }
            \dim_set:Nn \l_@@_bound_dim
              { \@@_use_punct_dim:nnn { bound } {#1} {#2} }
            \dim_set:Nn \l_@@_reverse_bound_dim
              {
                \@@_use_punct_dim:nnn { bound }
                  { \xeCJK_reverse:nnn {#1} \c_@@_left_tl \c_@@_right_tl }
                  {#2}
              }
            \UseInstance { xeCJK / punctuation } { \l_xeCJK_punct_style_tl }
            \xeCJK_punct_margin_process:NN {#1} {#2}
            \xeCJK_punct_offset_process:NN {#1} {#2}
          }
      }
  }
\dim_new:N \l_@@_bound_dim
\dim_new:N \l_@@_reverse_bound_dim
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_get_punct_kerning:NN}
% 标点挤压。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_get_punct_kerning:NN #1#2
  {
    \tl_if_exist:cF { \@@_punct_dim_csname:nnn { kern } {#1} {#2} }
      {
        \tl_if_eq:NNTF \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl
          {
            \@@_save_punct_dim:nnnn { kern } {#1} {#2} { \c_zero_dim }
            \@@_save_punct_dim:nnnn { break_kern } {#1} {#2} { \c_zero_dim }
          }
          {
            \UseInstance { xeCJK / punctuation } { \l_xeCJK_punct_style_tl }
            \xeCJK_punct_kerning_process:NN {#1} {#2}
          }
      }
  }
\cs_generate_variant:Nn \xeCJK_get_punct_kerning:NN { o }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_punct_margin_process:NN}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_punct_margin_process:NN #1#2
  {
    \dim_set:Nn \l_@@_tmp_dim
      {
        \bool_if:NTF \l_@@_enabled_global_setting_bool
          {
            \cs_if_exist_use:cTF { g_@@_punct_width/#2/tl }
              { \use_none:n }
              {
                \tl_if_empty:NTF \g_@@_punct_width_tl
                  { \use:n }
                  { \g_@@_punct_width_tl \use_none:n }
              }
          }
          { \use:n }
          {
            \@@_punct_if_middle:NTF {#2}
              { \@@_punct_width_or_ratio:nN { middle } {#2} }
              {
                \@@_punct_if_mixed_width:NTF {#2}
                  { \@@_punct_width_or_ratio:nN { mixed } {#2} }
                  { \@@_punct_width_or_ratio:nN { fixed } {#2} }
              }
          }
      }
    \dim_set:Nn \l_@@_tmp_dim
      {
        \dim_max:nn
          { \l_@@_margin_minimum_dim }
          {
            \dim_compare:nNnTF \l_@@_tmp_dim < \c_max_dim
              {
                \@@_punct_if_middle:NTF {#2}
                  {
                    (
                      \l_@@_tmp_dim - ( \@@_use_punct_dim:nn { dimen } {#2} )
                    ) / \c_two
                  }
                  {
                    \bool_if:NTF \l_@@_optimize_margin_bool
                      {
                        \dim_max:nn
                          { \dim_min:nn \l_@@_bound_dim \l_@@_reverse_bound_dim }
                      }
                      { \use:n }
                      {
                        \l_@@_tmp_dim - \l_@@_reverse_bound_dim
                        - ( \@@_use_punct_dim:nn { dimen } {#2} )
                      }
                  }
              }
              {
                \bool_if:NTF \l_@@_optimize_margin_bool
                  { \dim_min:nn { \l_@@_bound_dim } }
                  { \use:n }
                  {
                    \@@_punct_if_middle:NTF {#2}
                      {
                        \dim_compare:nNnTF \l_@@_middle_margin_width_dim < \c_max_dim
                          { \l_@@_middle_margin_width_dim }
                          {
                            \fp_use:N \l_@@_middle_margin_ratio_fp
                            \etex_dimexpr:D
                              ( \l_@@_bound_dim + \l_@@_reverse_bound_dim ) / \c_two
                            \scan_stop:
                          }
                      }
                      {
                        \@@_punct_if_mixed_width:NTF {#2}
                          { \@@_margin_width_or_ratio:n { mixed } }
                          { \@@_margin_width_or_ratio:n { fixed } }
                      }
                  }
              }
          }
      }
    \@@_save_punct_dim:nnnn { glue } {#1} {#2} { \l_@@_tmp_dim }
    \@@_save_punct_dim:nnnn { plus } {#1} {#2}
      {
        \dim_max:nn { \c_zero_dim }
          {
            \@@_punct_if_middle:NTF {#2}
              {
                ( \@@_use_punct_dim:nn { width } {#2} -
                  \@@_use_punct_dim:nn { dimen } {#2} ) / \c_two
                - \l_@@_tmp_dim
              }
              { \l_@@_bound_dim - \l_@@_tmp_dim }
          }
      }
    \@@_save_punct_dim:nnnn { minus } {#1} {#2}
      {
        \dim_max:nn { \c_zero_dim }
          {
            \@@_punct_if_middle:NTF {#2}
              { .5 \l_@@_tmp_dim }
              { \l_@@_tmp_dim - \l_@@_reverse_bound_dim }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_punct_offset_process:NN}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_punct_offset_process:NN #1#2
  {
    \dim_set:Nn \l_@@_tmp_dim
      {
        \bool_if:NTF \l_@@_enabled_global_setting_bool
          {
            \cs_if_exist_use:cTF { g_@@_punct_bound_width/#2/tl }
              { \use_none:n }
              {
                \tl_if_empty:NTF \g_@@_punct_bound_width_tl
                  { \use:n }
                  { \g_@@_punct_bound_width_tl \use_none:n }
              }
          }
          { \use:n }
          { \@@_punct_width_or_ratio:nN { bound } {#2} }
      }
    \dim_set:Nn \l_@@_tmp_dim
      {
        \bool_if:NTF \l_@@_enabled_hanging_bool
          { \use:n }
          { \dim_max:nn { \l_@@_margin_minimum_dim } }
          {
            \dim_compare:nNnTF \l_@@_tmp_dim < \c_max_dim
              {
                \@@_punct_if_middle:NTF {#2}
                  {
                    \l_@@_tmp_dim
                    - ( \@@_use_punct_dim:nnn { glue } {#1} {#2} )
                    - ( \@@_use_punct_dim:nn { dimen } {#2} )
                  }
                  {
                    \l_@@_tmp_dim - \l_@@_reverse_bound_dim
                    - ( \@@_use_punct_dim:nn { dimen } {#2} )
                  }
              }
              {
                \bool_if:NTF \l_@@_optimize_margin_bool
                  { \dim_min:nn { \l_@@_bound_dim } }
                  { \use:n }
                  { \@@_margin_width_or_ratio:n { bound } }
              }
          }
      }
    \@@_save_punct_dim:nnnn { offset } {#1} {#2} { \l_@@_tmp_dim }
    \@@_save_punct_dim:nnnn { rule } {#1} {#2}
      { - \l_@@_bound_dim + \l_@@_tmp_dim }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.7}{2013/08/25}{标点宽度设置禁用比例选项的值改为 \texttt{nan}。}
%
% \begin{macro}[internal]{\@@_punct_width_or_ratio:nN}
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_punct_width_or_ratio:nN #1#2
  {
    \dim_compare:nNnTF { \use:c { l_@@_#1_punct_width_dim } } < \c_max_dim
      { \use:c { l_@@_#1_punct_width_dim } }
      {
        \fp_compare:nNnTF { \use:c { l_@@_#1_punct_ratio_fp } } ? \c_zero_fp
          { \c_max_dim }
          {
            \fp_use:c { l_@@_#1_punct_ratio_fp }
            \etex_dimexpr:D \@@_use_punct_dim:nn { width } {#2} \scan_stop:
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_margin_width_or_ratio:n}
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_margin_width_or_ratio:n #1
  {
    \dim_compare:nNnTF { \use:c { l_@@_#1_margin_width_dim } } < \c_max_dim
      { \use:c { l_@@_#1_margin_width_dim } }
      {
        \fp_use:c { l_@@_#1_margin_ratio_fp }
        \etex_dimexpr:D \l_@@_bound_dim \scan_stop:
      }
    \bool_if:NT \l_@@_add_min_bound_to_margin_bool
      { + \dim_min:nn \l_@@_bound_dim \l_@@_reverse_bound_dim }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_punct_kerning_process:NN}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_punct_kerning_process:NN #1#2
  {
    \dim_set:Nn \l_@@_tmp_dim
      {
        \bool_if:nTF
          {
            \l_@@_enabled_global_setting_bool &&
            \tl_if_exist_p:c { g_@@_punct/kern/#1/#2/tl }
          }
          { \tl_use:c { g_@@_punct/kern/#1/#2/tl } }
          {
            \bool_if:NTF \l_@@_enabled_kerning_bool
              { \@@_calc_kerning_margin:NN {#1} {#2} }
              { \@@_original_kerning_margin:NN {#1} {#2} }
          }
      }
    \@@_save_punct_dim:nnnn { kern } {#1} {#2}
      {
        \l_@@_tmp_dim
        - ( \@@_use_punct_dim:nnn { bound } \c_@@_right_tl {#1} )
        - ( \@@_use_punct_dim:nnn { bound } \c_@@_left_tl  {#2} )
      }
    \@@_punct_if_right:NF {#2}
      {
        \@@_punct_if_right:NT {#1}
          {
            \@@_save_punct_dim:nnnn { break_kern } {#1} {#2}
              {
                \l_@@_tmp_dim
                - ( \@@_use_punct_dim:nnn { offset } \c_@@_right_tl {#1} )
                - ( \@@_use_punct_dim:nnn { offset } \c_@@_left_tl  {#2} )
              }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_original_kerning_margin:NN}
% 相邻两个标点符号之间的本来空白宽度。
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_original_kerning_margin:NN #1#2
  {
    \dim_eval:n
      {
        \@@_use_punct_dim:nnn
          { \@@_punct_if_right:NTF {#1} { glue } { bound } }
          { \c_@@_right_tl } {#1} +
        \@@_use_punct_dim:nnn
          { \@@_punct_if_right:NTF {#2} { bound } { glue } }
          { \c_@@_left_tl  } {#2}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_calc_kerning_margin:NN}
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_calc_kerning_margin:NN #1#2
  {
    \dim_max:nn
      { \l_@@_kerning_margin_minimum_dim }
      {
        \bool_if:NTF \l_@@_min_bound_to_kerning_bool
          { \@@_punct_min_bound:NN  {#1} {#2} }
          {
            \bool_if:NTF \l_@@_optimize_kerning_bool
              { \dim_max:nn { \@@_punct_min_bound:NN  {#1} {#2} } }
              { \use:n }
              {
                \dim_compare:nNnTF \l_@@_kerning_total_width_dim < \c_max_dim
                  { \@@_calc_kerning_margin:nNN \l_@@_kerning_total_width_dim }
                  {
                    \fp_compare:nNnTF \l_@@_kerning_total_ratio_fp ? \c_zero_fp
                      {
                        \xeCJK_if_same_class:NNTF {#1} {#2}
                          { \@@_kerning_width_or_ratio:nNN { same } }
                          { \@@_kerning_width_or_ratio:nNN { different } }
                      }
                      {
                        \@@_calc_kerning_margin:nNN
                          {
                            \fp_use:N \l_@@_kerning_total_ratio_fp
                            \etex_dimexpr:D
                              \@@_use_punct_dim:nn { width } {#1} +
                              \@@_use_punct_dim:nn { width } {#2}
                            \scan_stop:
                          }
                      }
                  }
                  {#1} {#2}
              }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_kerning_width_or_ratio:nNN}
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_kerning_width_or_ratio:nNN #1#2#3
  {
    \dim_compare:nNnTF { \use:c { l_@@_#1_align_margin_dim } } < \c_max_dim
      { \use:c { l_@@_#1_align_margin_dim } }
      {
        \fp_compare:nNnTF { \use:c { l_@@_#1_align_ratio_fp } } ? \c_zero_fp
          {
            \dim_compare:nNnTF \l_@@_kerning_margin_width_dim < \c_max_dim
              { \l_@@_kerning_margin_width_dim \use_none:n }
              { \fp_use:N \l_@@_kerning_margin_ratio_fp \use:n }
          }
          { \fp_use:c { l_@@_#1_align_ratio_fp } \use:n }
          { \etex_dimexpr:D \@@_original_kerning_margin:NN {#2} {#3} \scan_stop: }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_punct_min_bound:NN}
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_punct_min_bound:NN #1#2
  {
    \dim_max:nn
      {
        \dim_min:nn
          { \@@_use_punct_dim:nnn { bound } \c_@@_left_tl  {#1} }
          { \@@_use_punct_dim:nnn { bound } \c_@@_right_tl {#1} }
      }
      {
        \dim_min:nn
          { \@@_use_punct_dim:nnn { bound } \c_@@_left_tl  {#2} }
          { \@@_use_punct_dim:nnn { bound } \c_@@_right_tl {#2} }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_calc_kerning_margin:nNN}
% |#2| 和 |#3| 为相邻的两个标点，|#1| 为要确定的相邻两个标点总共占的宽度。
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_calc_kerning_margin:nNN #1#2#3
  {
    \dim_eval:n
      {
        (#1)
        - ( \@@_use_punct_dim:nnn
              { \@@_punct_if_right:NTF {#2} { bound } { glue } }
              { \c_@@_left_tl } {#2} )
        - ( \@@_use_punct_dim:nnn
              { \@@_punct_if_right:NTF {#3} { glue } { bound } }
              { \c_@@_right_tl } {#3} )
        - ( \@@_use_punct_dim:nn { dimen } {#2} )
        - ( \@@_use_punct_dim:nn { dimen } {#3} )
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_calc_punct_dimen:N}
% 计算标点的左右实际边距和实际尺寸。对于破折号，计算两标点之间的空白，保证它中间
% 不被断开。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_calc_punct_dimen:N #1
  {
    \@@_save_punct_dim:nnnn { bound } \c_@@_left_tl {#1}
      { \xeCJK_glyph_bounds:NN \c_one {#1} }
    \@@_save_punct_dim:nnnn { bound } \c_@@_right_tl {#1}
      { \xeCJK_glyph_bounds:NN \c_three {#1} }
    \dim_set:Nn \l_@@_tmp_dim
      {
        ( \@@_use_punct_dim:nnn { bound } \c_@@_left_tl  {#1} ) +
        ( \@@_use_punct_dim:nnn { bound } \c_@@_right_tl {#1} )
      }
    \@@_save_punct_dim:nnn { width } {#1}
      { \etex_fontcharwd:D \tex_font:D \xeCJK_token_value_charcode:N #1 }
    \@@_save_punct_dim:nnn { dimen } {#1}
      { \@@_use_punct_dim:nn { width } {#1} - \l_@@_tmp_dim }
    \@@_punct_if_long:NT {#1}
      {
        \@@_save_punct_dim:nnnn { kern } {#1} {#1}
          {
            \str_case:nnTF {#1}
              { { ^^^^2025 } { } { ^^^^2026 } { } }
              { \c_zero_dim }
              { - \l_@@_tmp_dim }
          }
      }
  }
\cs_generate_variant:Nn \xeCJK_calc_punct_dimen:N { f }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_glyph_bounds:NN}
% 用 \tn{XeTeXglyphbounds} 取得标点符号的上下左右空白。
%    \begin{macrocode}
\cs_new_nopar:Npn \xeCJK_glyph_bounds:NN #1#2
  {
    \dim_use:N \XeTeXglyphbounds #1 ~
    \XeTeXcharglyph \xeCJK_token_value_charcode:N #2 \exp_stop_f:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{PunctStyle}
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    PunctStyle .choice: ,
    PunctStyle              .default:n = { quanjiao } ,
    PunctStyle / halfwidth     .meta:n = { PunctStyle = banjiao } ,
    PunctStyle / fullwidth     .meta:n = { PunctStyle = quanjiao } ,
    PunctStyle / mixedwidth    .meta:n = { PunctStyle = kaiming } ,
    PunctStyle / marginkerning .meta:n = { PunctStyle = hangmobanjiao } ,
    PunctStyle / plain         .code:n =
      { \tl_set_eq:NN \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl } ,
    PunctStyle / unknown       .code:n =
      {
        \IfInstanceExistTF { xeCJK / punctuation } { \l_keys_value_tl }
          { \tl_set:Nx \l_xeCJK_punct_style_tl { \l_keys_value_tl } }
          { \@@_error:nx { punct-style-unknown } { \l_keys_value_tl } }
      }
  }
\tl_new:N \l_xeCJK_punct_style_tl
\tl_const:Nn \c_@@_punct_style_plain_tl { plain }
\@@_msg_new:nn { punct-style-unknown }
  {
    Punctuation~style~"#1"~is~unknown. \\\\
    The~available~styles~are~listed~as~follow.\\\\
    "plain,~\seq_use:Nnnn \g_@@_punct_style_seq { ~and~ } { ,~ } { ,~and~ }".\\
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKDeclarePunctStyle}
% 定义新的标点处理风格，已经存在的同名风格将被覆盖。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKDeclarePunctStyle { > { \TrimSpaces } m m }
  {
    \IfInstanceExistTF { xeCJK / punctuation } {#1}
      { \@@_warning:nx { punct-style-already-defined } {#1} }
      { \seq_gput_right:Nx \g_@@_punct_style_seq {#1} }
    \exp_args:Nnx \DeclareInstance { xeCJK / punctuation } {#1} { basic } {#2}
  }
\seq_new:N \g_@@_punct_style_seq
\@@_msg_new:nn { punct-style-already-defined }
  {
    Punctuation~style~"#1"~is~already~defined!. \\\\
    The~existing~style~of~"#1"~will~be~overwritten.\\
  }
\@onlypreamble \xeCJKDeclarePunctStyle
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKEditPunctStyle}
% 对已有的标点处理风格进行修改。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKEditPunctStyle { > { \TrimSpaces } m m }
  {
    \IfInstanceExistTF { xeCJK / punctuation } {#1}
      { \exp_args:Nnx \EditInstance { xeCJK / punctuation } {#1} {#2} }
      { \@@_error:nx { punct-style-unknown } {#1} }
  }
\@onlypreamble \xeCJKEditPunctStyle
%    \end{macrocode}
% \end{macro}
%
% 默认设置即为全角格式。
%    \begin{macrocode}
\xeCJKDeclarePunctStyle { quanjiao } { }
%    \end{macrocode}
%
%    \begin{macrocode}
\xeCJKDeclarePunctStyle { hangmobanjiao } { enabled-kerning = false }
%    \end{macrocode}
%
%    \begin{macrocode}
\xeCJKDeclarePunctStyle { banjiao }
  {
    fixed-punct-ratio   = 0.5  ,
    optimize-margin     = true ,
    kerning-total-ratio = 0.5  ,
    optimize-kerning    = true
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\xeCJKDeclarePunctStyle { kaiming }
  {
    fixed-punct-ratio   = 0.5  ,
    mixed-punct-ratio   = 0.8  ,
    optimize-margin     = true ,
    kerning-total-ratio = 0.5  ,
    optimize-kerning    = true
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\xeCJKDeclarePunctStyle { CCT }
  {
    fixed-punct-ratio   = 0.7  ,
    optimize-margin     = true ,
    kerning-total-ratio = 0.6  ,
    optimize-kerning    = true
  }
%    \end{macrocode}
%
% \subsection{后备字体}
%
% \begin{macro}{AutoFallBack}
% 后备字体的宏包选项声明。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    AutoFallBack .choice: ,
    AutoFallBack / true  .code:n =
      {
        \cs_if_eq:NNF \CJKsymbol \xeCJK_fallback_test_glyph:N
          {
            \cs_set_eq:NN \@@_fallback_save_CJKsymbol:N \CJKsymbol
            \cs_set_eq:NN \CJKsymbol \xeCJK_fallback_test_glyph:N
          }
      } ,
    AutoFallBack / false .code:n =
      {
        \cs_if_eq:NNT \CJKsymbol \xeCJK_fallback_test_glyph:N
          { \cs_set_eq:NN \CJKsymbol \@@_fallback_save_CJKsymbol:N }
      } ,
    AutoFallBack      .default:n = { true } ,
    fallback             .meta:n = { AutoFallBack = true }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_fallback_test_glyph:N}
% 测试当前字体中是否存在当前字符，如存在则直接输出，否则启用后备字体。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_fallback_test_glyph:N #1
  {
    \xeCJK_glyph_if_exist:NTF {#1}
      { \@@_fallback_save_CJKsymbol:N {#1} }
      {
        \xeCJK_class_group_begin:
        \tl_set_eq:NN \l_@@_fallback_family_tl \l_xeCJK_family_tl
        \xeCJK_fallback_loop:Nn {#1} { \l_xeCJK_family_tl/FallBack }
        \xeCJK_class_group_end:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.12}{2014/05/12}{更新 \cs{int_to_Hex:n}。}
%
% \begin{macro}[internal]{\xeCJK_fallback_loop:Nn}
% \changes{v3.1.0}{2012/11/19}{调整备用字体的循环方式。}
% \changes{v3.2.4}{2013/06/30}
% {使 \tn{CJKfamilydefault} 的 \texttt{FallBack} 设置全局可用。}
% 循环测试后备字体是否包含字符 |#1|。若后备字体中存在该字符或者再没有后备字体，则
% 结束循环。当前字体族没有备用字体时，使用 \tn{CJKfamilydefault} 的设置。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_fallback_loop:Nn #1#2
  {
    \xeCJK_family_if_exist:xTF {#2}
      {
        \tl_set:Nx \l_xeCJK_family_tl {#2}
        \tl_set_eq:NN \CJK@family \l_@@_fontspec_family_tl
        \xeCJK_select_font:
        \xeCJK_glyph_if_exist:NTF {#1}
          { \@@_fallback_save_CJKsymbol:N {#1} }
          { \xeCJK_fallback_loop:Nn {#1} { \l_xeCJK_family_tl/FallBack } }
      }
      {
        \str_if_eq_x:nnTF { \CJKfamilydefault } { \l_@@_fallback_family_tl }
          {
            \@@_warning:nxxx { missing-glyph }
              { \l_xeCJK_family_tl } {#1}
              { \int_to_Hex:n { `#1 } }
            \@@_fallback_save_CJKsymbol:N {#1}
          }
          {
            \tl_set:Nx \l_@@_fallback_family_tl { \CJKfamilydefault }
            \xeCJK_fallback_loop:Nn {#1} { \l_@@_fallback_family_tl }
          }
      }
  }
\@@_msg_new:nn { missing-glyph }
  {
    CJKfamily~`\@@_msg_family_map:n {#1}'~
    ( \prop_item:Nn \g_@@_family_font_name_prop {#1} )~
    does~not~contain~glyph~`#2'~(U+#3).\\
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\setCJKfallbackfamilyfont}
%    \begin{macrocode}
\NewDocumentCommand \setCJKfallbackfamilyfont { m O { } m }
  { \use:x { \xeCJK_set_family_fallback:nnn {#1} {#2} {#3} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_set_family_fallback:nnn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_set_family_fallback:nnn #1#2#3
  {
    \group_begin:
    \tl_set:Nn \l_@@_fallback_family_tl {#1}
    \prop_get:NVNF \g_@@_family_font_name_prop
      \l_@@_fallback_family_tl \l_@@_font_name_tl
      { \tl_clear:N \l_@@_font_name_tl }
    \clist_map_inline:nn {#3}
      {
        \tl_put_right:Nn \l_@@_fallback_family_tl { /FallBack }
        \@@_get_sub_features:Vn \l_@@_fallback_family_tl {##1}
        \clist_put_left:Nn \l_@@_sub_font_options_clist {#2}
        \xeCJK_set_family:VVV \l_@@_fallback_family_tl
          \l_@@_sub_font_options_clist \l_@@_sub_font_name_tl
      }
    \group_end:
  }
\tl_new:N \l_@@_fallback_family_tl
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{CJK 字体族声明方式}
%
%    \begin{macrocode}
\bool_new:N \g_@@_auto_fake_bold_bool
\bool_new:N \g_@@_auto_fake_slant_bool
\fp_new:N \g_@@_embolden_factor_fp
\fp_new:N \g_@@_slant_factor_fp
%    \end{macrocode}
%
% \begin{macro}{AutoFakeBold, AutoFakeSlant,EmboldenFactor,SlantFactor}
% 伪粗体和伪斜体的宏包选项声明。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    AutoFakeBold .choices:nn = { true , false }
      { \use:c { bool_gset_ \l_keys_choice_tl :N } \g_@@_auto_fake_bold_bool } ,
    AutoFakeBold / unknown .code:n =
      {
        \bool_gset_true:N  \g_@@_auto_fake_bold_bool
        \fp_gset:Nn \g_@@_embolden_factor_fp { \l_keys_value_tl }
      } ,
    AutoFakeBold  .default:n  = { true } ,
    AutoFakeSlant .choices:nn = { true , false }
      { \use:c { bool_gset_ \l_keys_choice_tl :N } \g_@@_auto_fake_slant_bool } ,
    AutoFakeSlant / unknown  .code:n =
      {
        \bool_gset_true:N  \g_@@_auto_fake_slant_bool
        \fp_gset:Nn \g_@@_slant_factor_fp { \l_keys_value_tl }
      } ,
    AutoFakeSlant  .default:n = { true } ,
    EmboldenFactor .fp_gset:N = \g_@@_embolden_factor_fp ,
    SlantFactor    .fp_gset:N = \g_@@_slant_factor_fp ,
    BoldFont  .meta:n = { AutoFakeBold  = true } ,
    boldfont  .meta:n = { AutoFakeBold  = true } ,
    SlantFont .meta:n = { AutoFakeSlant = true } ,
    slantfont .meta:n = { AutoFakeSlant = true }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.4}{2013/07/02}{内部调整分区字体的设置方法。}
%
% \begin{macro}[internal]{\xeCJK_new_sub_key:n,\g_@@_sub_key_seq}
% 用于定义 CJK 子区字体和备用字体的选项。
%    \begin{macrocode}
\seq_new:N \g_@@_sub_key_seq
\cs_new_protected_nopar:Npn \xeCJK_new_sub_key:n #1
  {
    \seq_gput_right:Nn \g_@@_sub_key_seq {#1}
    \keys_define:nn { xeCJK / features }
      {
        #1 .code:n =
          {
            \tl_if_blank:nTF {##1}
              {
                \prop_clear:N \l_@@_sub_key_prop
                \tl_put_right:Nn \l_@@_family_name_tl { /#1 }
                \clist_remove_all:Nn \l_@@_font_options_clist {#1}
              }
              {
                \str_if_eq:nnTF {##1} { * }
                  { \prop_put:Nnn \l_@@_sub_key_prop {#1} { \q_no_value } }
                  { \@@_get_sub_features:nn {#1} {##1} }
              }
          } ,
        #1 .default:n = { }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.4}{2013/07/02}{改进获取分区字体属性的办法。}
%
% \begin{macro}[internal]{\@@_get_sub_features:nn,\@@_get_sub_features:w}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_get_sub_features:nn #1#2
  {
    \tl_set:Nx \l_@@_tmp_tl { \xeCJK_tl_remove_outer_braces:n {#2} }
    \clist_clear:N \l_@@_sub_font_options_clist
    \exp_after:wN \@@_get_sub_features:w \l_@@_tmp_tl
      \q_mark [ \q_nil ] \q_mark \q_stop
    \tl_if_empty:NTF \l_@@_sub_font_name_tl
      { \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_font_name_tl }
      { \tl_replace_all:NnV \l_@@_sub_font_name_tl { * } \l_@@_font_name_tl }
    \prop_put:Nnx \l_@@_sub_key_prop {#1}
      {
        { \exp_not:V \l_@@_sub_font_options_clist }
        { \exp_not:V \l_@@_sub_font_name_tl }
      }
  }
\cs_new_protected_nopar:Npn \@@_get_sub_features:w #1 [#2] #3 \q_mark #4 \q_stop
  {
    \quark_if_nil:nTF {#2}
      { \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_tmp_tl }
      {
        \tl_set:Nx \l_@@_sub_font_name_tl
          { \xeCJK_tl_remove_outer_braces:n {#3} }
        \tl_if_empty:NTF \l_@@_sub_font_name_tl
          { \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_tmp_tl }
          { \clist_set:Nn \l_@@_sub_font_options_clist {#2} }
      }
  }
\tl_new:N \l_@@_sub_family_name_tl
\tl_new:N \l_@@_sub_font_name_tl
\clist_new:N \l_@@_sub_font_options_clist
\cs_generate_variant:Nn \@@_get_sub_features:nn { V }
\cs_generate_variant:Nn \tl_replace_all:Nnn { NnV }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{FallBack}
%    \begin{macrocode}
\xeCJK_new_sub_key:n { FallBack }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{BoldFont,ItalicFont}
% 调用字体的属性声明，同 \pkg{fontspec} 宏包。
%    \begin{macrocode}
\keys_define:nn { xeCJK / features }
  {
    BoldFont   .tl_set:N = \l_@@_font_name_bf_tl ,
    ItalicFont .tl_set:N = \l_@@_font_name_it_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.6}{2013/07/31}{\texttt{AutoFakeBold} 和 \texttt{AutoFakeSlant}
% 选项直接使用 \pkg{fontspec} 的设置，修正不能调用相应实际字体的问题。}
%
% \begin{macro}[internal]{AutoFakeBold, AutoFakeSlant}
%    \begin{macrocode}
\keys_define:nn { xeCJK / features }
  {
    AutoFakeBold  .choice: ,
    AutoFakeBold / true    .code:n =
      {
        \bool_set_true:N \l_@@_auto_fake_bold_bool
        \fp_set_eq:NN \l_@@_embolden_factor_fp \g_@@_embolden_factor_fp
      } ,
    AutoFakeBold / false   .code:n =
      { \bool_set_false:N \l_@@_auto_fake_bold_bool } ,
    AutoFakeBold / unknown .code:n =
      {
        \bool_set_true:N \l_@@_auto_fake_bold_bool
        \fp_set:Nn \l_@@_embolden_factor_fp { \l_keys_value_tl }
      } ,
    AutoFakeBold .default:n  = { true } ,
    AutoFakeSlant  .choice: ,
    AutoFakeSlant / true    .code:n =
      {
        \bool_set_true:N \l_@@_auto_fake_slant_bool
        \fp_set_eq:NN \l_@@_slant_factor_fp \g_@@_slant_factor_fp
      } ,
    AutoFakeSlant / false   .code:n =
      { \bool_set_false:N \l_@@_auto_fake_slant_bool } ,
    AutoFakeSlant / unknown .code:n =
      {
        \bool_set_true:N \l_@@_auto_fake_slant_bool
        \fp_set:Nn \l_@@_slant_factor_fp { \l_keys_value_tl }
      } ,
    AutoFakeSlant .default:n  = { true }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_set_family_initial:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_set_family_initial:
  {
    \int_gincr:N \g_@@_family_int
    \prop_clear:N \l_@@_sub_key_prop
    \tl_clear:N \l_@@_font_name_bf_tl
    \tl_clear:N \l_@@_font_name_it_tl
    \clist_clear:N \l_@@_fontspec_options_clist
    \bool_set_eq:NN \l_@@_auto_fake_bold_bool  \g_@@_auto_fake_bold_bool
    \bool_set_eq:NN \l_@@_auto_fake_slant_bool \g_@@_auto_fake_slant_bool
    \fp_set_eq:NN \l_@@_embolden_factor_fp \g_@@_embolden_factor_fp
    \fp_set_eq:NN \l_@@_slant_factor_fp    \g_@@_slant_factor_fp
  }
\int_new:N \g_@@_family_int
\prop_new:N \l_@@_sub_key_prop
\clist_new:N \l_@@_fontspec_options_clist
\bool_new:N \l_@@_auto_fake_bold_bool
\bool_new:N \l_@@_auto_fake_slant_bool
\fp_new:N \l_@@_embolden_factor_fp
\fp_new:N \l_@@_slant_factor_fp
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_set_family:nnn}
% 设置一个 CJK 新字体族，与 \tn{newfontfamily} 类似，增加 |FallBack| 选项。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_set_family:nnn #1#2#3
  {
    \group_begin:
    \@@_set_family_initial:
    \tl_set:Nn \l_@@_family_name_tl {#1}
    \clist_set:Nn \l_@@_font_options_clist {#2}
    \tl_set:Nn \l_@@_font_name_tl {#3}
    \clist_concat:NNN \l_@@_font_options_clist
      \g_@@_default_features_clist \l_@@_font_options_clist
    \@@_remove_duplicate_keys:N \l_@@_font_options_clist
    \keys_set_known:nVN { xeCJK / features }
      \l_@@_font_options_clist \l_@@_fontspec_options_clist
    \@@_parse_font_shape:
    \@@_check_family:V \l_@@_family_name_tl
    \@@_gset_family_cs:x { \l_@@_family_name_tl }
    \@@_save_family_info:
    \@@_set_sub_block_family:
    \group_end:
  }
\tl_new:N \l_@@_family_name_tl
\tl_new:N \l_@@_font_name_tl
\clist_new:N \l_@@_font_options_clist
\cs_generate_variant:Nn \xeCJK_set_family:nnn { Vnn , VVV , Voo }
\cs_new_protected_nopar:Npn \xeCJK_set_family:xxx #1#2#3
  { \use:x { \xeCJK_set_family:nnn {#1} {#2} {#3} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_remove_duplicate_keys:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_remove_duplicate_keys:N #1
  {
    \prop_clear:N \l_@@_font_options_prop
    \keyval_parse:NNV \@@_prop_put_aux:n \@@_prop_put_aux:nn #1
    \clist_clear:N #1
    \prop_map_inline:Nn \l_@@_font_options_prop
      {
        \tl_set:No \l_@@_tmp_tl { \use_ii:nn ##2 }
        \tl_if_blank:VTF \l_@@_tmp_tl
          { \clist_put_right:No #1 { \use_i:nn ##2 } }
          {
            \clist_put_right:Nx #1
              { \exp_not:o { \use_i:nn ##2 } = { \exp_not:V \l_@@_tmp_tl } }
          }
      }
  }
\prop_new:N \l_@@_font_options_prop
\cs_generate_variant:Nn \keyval_parse:NNn { NNV }
\cs_new_protected_nopar:Npn \@@_prop_put_aux:n #1
  { \prop_put:Nnn \l_@@_font_options_prop {#1} { {#1} {  } } }
\cs_new_protected_nopar:Npn \@@_prop_put_aux:nn #1#2
  { \prop_put:Nnn \l_@@_font_options_prop {#1} { {#1} {#2} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_gset_family_cs:x}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_gset_family_cs:x #1
  {
    \cs_gset_protected_nopar:cpx { \@@_family_csname:n {#1} }
      {
        \group_begin:
        \exp_not:n { \cs_set_eq:NN \@@_update_family:nn \use_none:nn }
        \exp_not:n { \fontspec_set_family:Nnn \l_@@_fontspec_family_tl }
          { \exp_not:V \l_@@_fontspec_options_clist }
          { \exp_not:V \l_@@_font_name_tl }
        \@@_gset_family_nfss_cs:xx
          {#1} { \exp_not:N \l_@@_fontspec_family_tl }
        \exp_not:N \exp_args:NNNo \group_end:
        \tl_set:Nn \exp_not:N \l_@@_fontspec_family_tl
          { \exp_not:N \l_@@_fontspec_family_tl }
      }
  }
\tl_new:N \l_@@_fontspec_family_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_check_family:n}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_check_family:n #1
  {
    \prop_gpop:NnNT \g_@@_family_font_name_prop {#1} \l_@@_tmp_tl
      {
        \prop_gpop:NnNT \g_@@_family_name_prop {#1} \l_@@_tmp_tl
          {
            \cs_undefine:c { \@@_family_csname:n {#1} }
            \cs_undefine:c { \@@_family_nfss_csname:n {#1} }
          }
        \@@_warning:nxx { CJKfamily-redef } {#1} { \l_@@_tmp_tl }
      }
  }
\cs_generate_variant:Nn \@@_check_family:n { V }
\@@_msg_new:nn { CJKfamily-redef }
  { Redefining~CJKfamily~`\@@_msg_family_map:n {#1}'~(#2). }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_parse_font_shape:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_parse_font_shape:
  {
    \tl_if_blank:VTF \l_@@_font_name_bf_tl
      {
        \bool_if:NT \l_@@_auto_fake_bold_bool
          {
            \clist_put_right:Nx \l_@@_fontspec_options_clist
              { AutoFakeBold = { \fp_use:N \l_@@_embolden_factor_fp } }
          }
      }
      {
        \clist_put_right:Nx \l_@@_fontspec_options_clist
          { BoldFont = { \exp_not:V \l_@@_font_name_bf_tl } }
      }
    \tl_if_blank:VTF \l_@@_font_name_it_tl
      {
        \bool_if:NT \l_@@_auto_fake_slant_bool
          {
            \clist_put_right:Nx \l_@@_fontspec_options_clist
              { AutoFakeSlant = { \fp_use:N \l_@@_slant_factor_fp } }
          }
      }
      {
        \clist_put_right:Nx \l_@@_fontspec_options_clist
          { ItalicFont = { \exp_not:V \l_@@_font_name_it_tl } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal,var]
%  {\g_@@_family_name_prop,\g_@@_family_font_name_prop,\g_@@_family_font_options_prop}
%    \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{macro}
%
% \begin{macro}[internal]{\@@_save_family_info:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_save_family_info:
  {
    \prop_gput:NVV \g_@@_family_font_name_prop
      \l_@@_family_name_tl \l_@@_font_name_tl
    \prop_gput:NVV \g_@@_family_font_options_prop
      \l_@@_family_name_tl \l_@@_font_options_clist
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_set_sub_block_family:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_set_sub_block_family:
  {
    \prop_map_inline:Nn \l_@@_sub_key_prop
      {
        \tl_set:Nx \l_@@_sub_family_name_tl { \l_@@_family_name_tl/##1 }
        \quark_if_no_value:nTF {##2}
          { \@@_copy_sub_family:n {##1} }
          {
            \xeCJK_set_family:Voo \l_@@_sub_family_name_tl
              { \use_i:nn ##2 } { \use_ii:nn ##2 }
          }
      }
  }
\cs_new_protected_nopar:Npn \@@_copy_sub_family:n #1
  {
    \@@_check_family:V \l_@@_sub_family_name_tl
    \prop_get:NVNT \g_@@_family_font_name_prop
      \l_@@_family_name_tl \l_@@_sub_font_name_tl
      {
        \prop_gput:NVV \g_@@_family_font_name_prop
          \l_@@_sub_family_name_tl \l_@@_sub_font_name_tl
      }
    \prop_get:NVNT \g_@@_family_font_options_prop
      \l_@@_family_name_tl \l_@@_sub_font_options_clist
      {
        \clist_remove_all:Nn \l_@@_sub_font_options_clist { #1 = * }
        \prop_gput:NVV \g_@@_family_font_options_prop
          \l_@@_sub_family_name_tl \l_@@_sub_font_options_clist
      }
    \cs_gset_protected_nopar:cpx
      { \@@_family_csname:n { \l_@@_sub_family_name_tl } }
      {
        \xeCJK_family_if_exist:xT { \l_@@_family_name_tl }
          {
            \@@_gset_family_nfss_cs:xx
              { \l_@@_sub_family_name_tl }
              { \exp_not:N \l_@@_fontspec_family_tl }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_copy_family:nn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_copy_family:nn #1#2
  {
    \xeCJK_family_if_exist:nT {#2}
      {
        \prop_gput:NnV \g_@@_family_name_prop
          {#1} \l_@@_fontspec_family_tl
        \tl_map_inline:nn
          {
            \g_@@_family_font_name_prop
            \g_@@_family_font_options_prop
          }
          {
            \prop_get:NnNT ##1 {#2} \l_@@_tmp_tl
              { \prop_gput:NnV ##1 {#1} \l_@@_tmp_tl }
          }
        \cs_gset_eq:cc
          { \@@_family_nfss_csname:n {#1} }
          { \@@_family_nfss_csname:n {#2} }
      }
  }
\cs_generate_variant:Nn \@@_copy_family:nn { xx }
%    \end{macrocode}
% \end{macro}
%
% \subsection{字体切换}
%
% \begin{macro}[internal]{\l_xeCJK_current_font_tl,\xeCJK_select_font:}
% 缓存当前字体的原始格式，以加速编译。
%    \begin{macrocode}
\tl_new:N \l_xeCJK_current_font_tl
\tl_set:Nn \l_xeCJK_current_font_tl { \@@_font_csname:n { \CJK@family } }
\cs_new_nopar:Npn \@@_font_csname:n #1 { xeCJK/#1/\f@series/\f@shape/\f@size }
\cs_new_protected_nopar:Npn \xeCJK_select_font:
  {
    \exp_args:Nc \cs_if_exist_use:NF { \l_xeCJK_current_font_tl }
      {
        \@@_family_use:x { \l_xeCJK_family_tl }
        \xeCJK_font_gset_to_current:c { \l_xeCJK_current_font_tl }
      }
  }
\tl_new:N \l_@@_current_coor_tl
\cs_new_eq:NN \xeCJK@setfont \xeCJK_select_font:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_switch_font:nn}
% \changes{v3.1.0}{2012/11/18}{改进定义，加快切换速度。}
% 两个 CJK 分区之间的字体切换。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_switch_font:nn #1#2
  {
    \str_if_eq:nnF {#1} {#2}
      {
        \@@_info:nxx { CJK-block } {#1} {#2}
        \str_if_eq:nnTF {#2} { CJK }
          { \xeCJK_select_font: }
          { \@@_block_select_font:n {#2} }
      }
  }
\@@_msg_new:nn { CJK-block } { Switch~from~block~`#1'~to~`#2'. }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_block_select_font:n}
% 若当前 CJK 字体族没有定义子分区 |#1| 的字体，则使用 \tn{CJKfamilydefault} 的对应
% 分区字体；若 \tn{CJKfamilydefault} 也没有定义该分区字体，则使用当前 CJK 字体族的
% 主分区字体。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_block_select_font:n #1
  {
    \exp_args:Nc \cs_if_exist_use:NF { \@@_font_csname:n { \CJK@family/#1 } }
      {
        \xeCJK_family_if_exist:xF { \l_xeCJK_family_tl/#1 }
          {
            \@@_copy_family:xx { \l_xeCJK_family_tl/#1 }
              {
                \cs_if_exist:cTF
                  { \@@_family_csname:n { \CJKfamilydefault/#1 } }
                  { \CJKfamilydefault/#1 } { \l_xeCJK_family_tl }
              }
          }
        \@@_family_use:x { \l_xeCJK_family_tl/#1 }
        \xeCJK_font_gset_to_current:c
          { \@@_font_csname:n { \CJK@family/#1 } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {\@@_family_csname:n,\@@_family_nfss_csname:n,
%    \@@_family_use:x,\@@_gset_family_nfss_cs:xx}
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_family_csname:n #1 { xeCJK/family/#1 }
\cs_new_nopar:Npn \@@_family_nfss_csname:n #1 { xeCJK/family/nfss/#1 }
\cs_new_nopar:Npn \@@_family_use:x #1 { \use:c { \@@_family_nfss_csname:n {#1} } }
\cs_new_protected_nopar:Npn \@@_gset_family_nfss_cs:xx #1#2
  {
    \prop_gput:Nxx \g_@@_family_name_prop {#1} {#2}
    \cs_gset_protected_nopar:cpx { \@@_family_nfss_csname:n {#1} }
      {
        \exp_not:N \fontencoding { \c_@@_encoding_tl }
        \tl_set:Nx \exp_not:N \f@family {#2}
        \exp_not:N \selectfont
      }
  }
\cs_generate_variant:Nn \prop_gput:Nnn { Nxx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[TF,internal]{\xeCJK_family_if_exist:n}
%    \begin{macrocode}
\prg_new_protected_conditional:Npnn \xeCJK_family_if_exist:n #1 { T , F , TF }
  {
    \prop_get:NnNTF \g_@@_family_name_prop {#1} \l_@@_fontspec_family_tl
      { \prg_return_true: }
      {
        \exp_args:Nc \cs_if_exist_use:NTF { \@@_family_csname:n {#1} }
          { \prg_return_true: } { \prg_return_false: }
      }
  }
\cs_generate_variant:Nn \xeCJK_family_if_exist:nT  { x }
\cs_generate_variant:Nn \xeCJK_family_if_exist:nF  { x }
\cs_generate_variant:Nn \xeCJK_family_if_exist:nTF { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CJKfamily}
% 用于切换 CJK 字体族。
%    \begin{macrocode}
\NewDocumentCommand \CJKfamily { t+ t- m }
  {
    \xeCJK_if_blank_x:nTF {#3}
      {
        \IfBooleanF {#1} { \IfBooleanF {#2} { \use_none:nn } }
        \xeCJK_family_if_exist_use:x { \l_xeCJK_family_tl }
      }
      {
        \IfBooleanTF {#2} { \xeCJK_family_if_exist_use:x {#3} }
          {
            \xeCJK_family_if_exist:xTF {#3}
              {
                \tl_set:Nx \l_xeCJK_family_tl {#3}
                \tl_set_eq:NN \CJK@family \l_@@_fontspec_family_tl
                \IfBooleanT {#1} { \@@_family_use:x {#3} }
              }
              { \@@_family_unknown_warning:x {#3} }
          }
      }
    \tex_ignorespaces:D
  }
\cs_new_protected_nopar:Npn \xeCJK_switch_family:n #1
  {
    \xeCJK_family_if_exist:xTF {#1}
      {
        \tl_set:Nx \l_xeCJK_family_tl {#1}
        \tl_set_eq:NN \CJK@family \l_@@_fontspec_family_tl
      }
      { \@@_family_unknown_warning:x {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\l_xeCJK_family_tl,\CJK@family}
% 用于保存文档当前正在使用的 CJK 字体族。
% \changes{v3.2.0}{2013/04/14}{不将其初始化为 \tn{CJKfamilydefault}。}
%    \begin{macrocode}
\tl_new:N \l_xeCJK_family_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\CJK@family}
% 用于保存实际的字体族名称。
% \changes{v3.2.11}{2014/03/29}{引入 \tn{CJK@family} 保存实际的字体族名。}
%    \begin{macrocode}
\tl_new:N \CJK@family
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_gobble_CJKfamily:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_gobble_CJKfamily:
  { \cs_set_eq:NN \CJKfamily \@@_gobble_CJKfamily:wn }
\DeclareExpandableDocumentCommand \@@_gobble_CJKfamily:wn { t+ t- m } {  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_family_if_exist_use:x}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_family_if_exist_use:x #1
  {
    \xeCJK_family_if_exist:xTF {#1}
      { \@@_family_use:x {#1} }
      { \@@_family_unknown_warning:x {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_family_unknown_warning:n}
% \changes{v3.1.2}{2013/01/01}
% {在没有定义任何 CJK 字体的情况下，不再重复给出字体没有定义的警告。}
%    \begin{macrocode}
\cs_new_protected_nopar: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}
            \@@_warning:nx { CJKfamily-Unknown } {#1}
          }
      }
  }
\cs_generate_variant:Nn \@@_family_unknown_warning:n { x }
\seq_new:N \g_@@_unknown_family_seq
\@@_msg_new:nn { CJKfamily-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_nopar:Npn \@@_msg_def_family_map:n #1
  {
    \str_case_x: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_nopar:Npn \@@_msg_family_map:n #1
  {
    \str_case_x: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}{\setCJKmainfont,\setCJKsansfont,\setCJKmonofont}
% 设置文档的 CJK 普通字体、无衬线和等宽字体。
% \changes{v3.2.0}{2013/04/14}{定义中加入 \tn{normalfont}。}
%    \begin{macrocode}
\NewDocumentCommand \setCJKmainfont { O { } m }
  {
    \xeCJK_set_family:xxx { \CJKrmdefault } {#1} {#2}
    \normalfont
  }
\cs_new_eq:NN \setCJKromanfont \setCJKmainfont
\NewDocumentCommand \setCJKsansfont { O { } m }
  {
    \xeCJK_set_family:xxx { \CJKsfdefault } {#1} {#2}
    \normalfont
  }
\NewDocumentCommand \setCJKmonofont { O { } m }
  {
    \xeCJK_set_family:xxx { \CJKttdefault } {#1} {#2}
    \normalfont
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\@onlypreamble \setCJKmainfont
\@onlypreamble \setCJKmathfont
\@onlypreamble \setCJKsansfont
\@onlypreamble \setCJKmonofont
\@onlypreamble \setCJKromanfont
%    \end{macrocode}
%
% \begin{macro}{\setCJKfamilyfont, \newCJKfontfamily, \CJKfontspec}
% 分别用于预声明 CJK 字体和随机调用 CJK 字体。
%    \begin{macrocode}
\NewDocumentCommand \setCJKfamilyfont { m O { } m }
  { \xeCJK_set_family:xxx {#1} {#2} {#3} }
\NewDocumentCommand \newCJKfontfamily { o m O { } m }
  {
    \tl_set:Nx \l_@@_tmp_tl { \IfNoValueTF {#1} { \cs_to_str:N #2 } {#1} }
    \cs_new_protected_nopar:Npx #2 { \xeCJK_switch_family:n { \l_@@_tmp_tl } }
    \xeCJK_set_family:xxx { \l_@@_tmp_tl } {#3} {#4}
  }
\NewDocumentCommand \CJKfontspec { O { } m }
  {
    \use:x { \xeCJK_fontspec:nn {#1} {#2} }
    \tex_ignorespaces:D
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_fontspec:nn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_fontspec:nn #1#2
  {
    \prop_get:NnNTF \g_@@_fontspec_prop
      { CJKfontspec/#1/#2/id } \l_xeCJK_family_tl
      { \xeCJK_switch_family:n { \l_xeCJK_family_tl } }
      {
        \@@_fontspec:xnn
          { CJKfontspec ( \int_eval:n { \g_@@_family_int + \c_one } ) }
          {#1} {#2}
      }
  }
\cs_new_protected_nopar:Npn \@@_fontspec:nnn #1#2#3
  {
    \prop_gput:Nnn \g_@@_fontspec_prop { CJKfontspec/#2/#3/id } {#1}
    \xeCJK_set_family:nnn {#1} {#2} {#3}
    \xeCJK_switch_family:n {#1}
  }
\cs_generate_variant:Nn \xeCJK_fontspec:nn { VV }
\cs_generate_variant:Nn \@@_fontspec:nnn { x }
\prop_new:N \g_@@_fontspec_prop
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\defaultCJKfontfeatures, \addCJKfontfeatures}
% \changes{v3.2.4}{2013/06/30}{可以单独增加当前各个分区字体的属性。}
% 分别用于设置 CJK 字体的默认属性和增加当前 CJK 字体的属性。
%    \begin{macrocode}
\clist_new:N \g_@@_default_features_clist
\NewDocumentCommand \defaultCJKfontfeatures { m }
  { \clist_gset:Nn \g_@@_default_features_clist {#1} }
\@onlypreamble \defaultCJKfontfeatures
\NewDocumentCommand \addCJKfontfeatures { s O { } m }
  {
    \xeCJK_add_font_features:Nxx #1 {#2} {#3}
    \tex_ignorespaces:D
  }
\cs_new_eq:NN \addCJKfontfeature \addCJKfontfeatures
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_add_font_features:Nnn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_add_font_features:Nnn #1#2#3
  {
    \prop_get:NVNTF \g_@@_family_font_name_prop
      \l_xeCJK_family_tl \l_@@_font_name_tl
      {
        \clist_set:Nn \l_@@_add_font_features_clist {#3}
        \seq_map_inline:Nn \g_@@_sub_key_seq
          { \clist_remove_all:Nn \l_@@_add_font_features_clist {##1} }
        \seq_clear:N \l_@@_sub_key_seq
        \clist_clear:N \l_@@_add_block_features_clist
        \clist_map_inline:nn {#2}
          {
            \seq_if_in:NnTF \g_@@_sub_key_seq {##1}
              {
                \seq_put_right:Nn \l_@@_sub_key_seq {##1}
                \@@_add_sub_class_features:n {##1}
              }
              { \@@_warning:nx { SubBlock-undefined } {##1} }
          }
        \bool_if:nT { #1 && \seq_if_empty_p:N \l_@@_sub_key_seq }
          {
            \seq_map_function:NN
              \g_@@_sub_key_seq \@@_add_sub_class_features:n
          }
        \prop_get:NVNT \g_@@_family_font_options_prop
          \l_xeCJK_family_tl \l_@@_font_options_clist
          {
            \bool_if:nT
              { \seq_if_empty_p:N \l_@@_sub_key_seq || #1 }
              {
                \clist_concat:NNN \l_@@_font_options_clist
                  \l_@@_font_options_clist \l_@@_add_font_features_clist
              }
            \clist_concat:NNN \l_@@_font_options_clist
              \l_@@_font_options_clist \l_@@_add_block_features_clist
          }
        \xeCJK_fontspec:VV \l_@@_font_options_clist \l_@@_font_name_tl
      }
      { \@@_warning:n { addCJKfontfeature-ignored } }
  }
\clist_new:N \l_@@_add_font_features_clist
\clist_new:N \l_@@_add_block_features_clist
\cs_generate_variant:Nn \xeCJK_add_font_features:Nnn { Nxx , Nnx }
\@@_msg_new:nn { addCJKfontfeature-ignored }
  {
    \token_to_str:N \addCJKfontfeature (s)~ignored.\\\\
    It~cannot~be~used~with~a~font~that~wasn't~selected~by~xeCJK.
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_add_sub_class_features:n}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_add_sub_class_features:n #1
  {
    \prop_get:NoNTF \g_@@_family_font_name_prop
      { \l_xeCJK_family_tl/#1 } \l_@@_sub_font_name_tl
      {
        \prop_get:NoN \g_@@_family_font_options_prop
          { \l_xeCJK_family_tl/#1 } \l_@@_sub_font_options_clist
      }
      {
        \prop_get:NxNTF \g_@@_family_font_name_prop
          { \CJKfamilydefault/#1 } \l_@@_sub_font_name_tl
          {
            \prop_get:NxN \g_@@_family_font_options_prop
              { \CJKfamilydefault/#1 } \l_@@_sub_font_options_clist
          }
          {
            \prop_get:NVN \g_@@_family_font_options_prop
              \l_xeCJK_family_tl \l_@@_sub_font_options_clist
            \tl_set_eq:NN \l_@@_sub_font_name_tl \l_@@_font_name_tl
          }
      }
    \clist_concat:NNN \l_@@_sub_font_options_clist
      \l_@@_sub_font_options_clist \l_@@_add_font_features_clist
    \clist_put_right:Nx \l_@@_add_block_features_clist
      {
        #1 =
          {
            [ \exp_not:V \l_@@_sub_font_options_clist ]
            { \exp_not:V \l_@@_sub_font_name_tl }
          }
      }
  }
\cs_generate_variant:Nn \prop_get:NnN   { Nx }
\cs_generate_variant:Nn \prop_get:NnNTF { Nx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{LoadFandol}
% \changes{v3.2.10}{2014/03/01}{当没有设置字体时，使用 Fandol 字体系列。}
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  { LoadFandol .bool_gset:N = \g_@@_fandol_bool }
\cs_new_protected_nopar:Npn \@@_load_fandol:
  {
    \setCJKmainfont
      [ BoldFont = FandolSong-Bold , ItalicFont = FandolKai ] { FandolSong-Regular }
    \setCJKsansfont [ BoldFont = FandolHei-Bold ] { FandolHei-Regular }
    \setCJKmonofont { FandolFang }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.1.2}{2013/01/01}{修正重定义 \tn{CJKfamilydefault} 无效的问题，恢复容错能力。}
% \changes{v3.2.13}{2014/06/02}{自动调整 \tn{CJKfamilydefault} 时，只将 \tn{familydefault} 展开一次。}
%
% 在导言区结束的时候，若没有声明 CJK 字体，则给出一个警告。如果 \tn{CJKfamilydefault}
% 没有被更改，则在此时根据西文字体的情况更新 \tn{CJKfamilydefault}。
% 如果 \tn{CJKfamilydefault} 对应的字体族没有定义，则使用 \tn{CJKrmdefault} 作为
% 默认字体族。若 \tn{CJKrmdefault} 也没有定义，则使用在导言区设置的第一个 CJK 字体
% 作为默认字体族。最后设置数学字体。
%    \begin{macrocode}
\@@_at_end_preamble:n
  {
    \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:
      }
    \prop_if_empty:NTF \g_@@_family_font_name_prop
      {
        \bool_if:NTF \g_@@_fandol_bool
          {
            \@@_warning:n { fandol }
            \@@_load_fandol:
            \use:n
          }
          {
            \@@_warning:nx { no-CJKfamily } { \CJKfamilydefault }
            \use_none:n
          }
      }
      { \use:n }
      {
        \xeCJK_family_if_exist:xF { \CJKfamilydefault }
          {
            \tl_set_eq:NN \l_@@_tmp_tl \CJKfamilydefault
            \str_if_eq_x:nnTF { \CJKfamilydefault } { \CJKrmdefault }
              { \use:n }
              {
                \xeCJK_family_if_exist:xTF { \CJKrmdefault }
                  { \tl_gset:Nn \CJKfamilydefault { \CJKrmdefault } }
              }
              {
                \prop_map_inline:Nn \g_@@_family_font_name_prop
                  {
                    \prop_map_break:n
                      { \tl_gset_rescan:Nnn \CJKfamilydefault { } {#1} }
                  }
              }
            \@@_warning:nxx { CJKfamilydefault-undefined }
              { \l_@@_tmp_tl } { \CJKfamilydefault }
          }
        \xeCJK_switch_family:n { \CJKfamilydefault }
        \bool_if:NT \g_@@_math_bool { \xeCJK_set_mathfont: }
      }
  }
\@@_msg_new:nn { no-CJKfamily }
  {
    It~seems~that~you~have~not~declare~a~CJKfamily.\\
    If~you~want~to~use~xeCJK~in~the~right~way,~you~should~use\\\\
    `\@@_msg_def_family_map:n {#1}'\\\\
    in~the~preamble~to~declare~the~default~CJKfamily.\\
  }
\@@_msg_new:nn { CJKfamilydefault-undefined }
  {
    Undefined~CJK~default~family~`\@@_msg_family_map:n {#1}'~
    has~been~replaced~by~`\@@_msg_family_map:n {#2}'.\\\\
    Try~to~use~`\@@_msg_def_family_map:n {#1}'~to~define~it.
  }
\@@_msg_new:nn { fandol }
  {
    Fandol~is~being~set~as~the~default~font~for~CJK~text.\\
    Please~make~sure~it~has~been~properly~installed.
  }
%    \end{macrocode}
%
% \subsection{数学字体设置}
%
% \begin{macro}{CJKmath}
% 是否启用 CJK 数学字体的宏包选项。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options } { CJKmath .bool_gset:N = \g_@@_math_bool }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\setCJKmathfont}
% 设置 CJK 数学字体。
%    \begin{macrocode}
\NewDocumentCommand \setCJKmathfont { O { } m }
  { \xeCJK_set_family:xxx { \c_@@_math_tl } {#1} {#2} }
\tl_const:Nn \c_@@_math_tl { CJKmath }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_set_mathfont:}
% \changes{v3.2.6}{2013/08/01}{设置粗体时先检查对应字体是否存在。}
% \changes{v3.2.7}{2013/11/09}{将 CJK 字符的数学归类由 $7$ 改为 $0$，解决汉字路径的问题。}
% \changes{v3.2.13}{2014/06/20}{修复参数类型错误。}
% 当没有设置 CJK 数学字体时，使用 \tn{CJKfamilydefault} 作为数学字体。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_set_mathfont:
  {
    \xeCJK_family_if_exist:xTF { \c_@@_math_tl }
      { \use:n }
      {
        \xeCJK_family_if_exist:xTF { \CJKfamilydefault }
          { \use:n } { \use_none:n }
      }
      {
        \tl_const:Nx \c_@@_math_family_tl { \l_@@_fontspec_family_tl }
        \DeclareSymbolFont { \c_@@_math_tl } { \c_@@_encoding_tl }
          { \c_@@_math_family_tl } { \mddefault } { \shapedefault }
        \cs_if_free:cF
          { \c_@@_encoding_tl/\c_@@_math_family_tl/\bfdefault/\shapedefault }
          {
            \SetSymbolFont { \c_@@_math_tl } { bold } { \c_@@_encoding_tl }
              { \c_@@_math_family_tl } { \bfdefault } { \shapedefault }
          }
        \int_const:Nn \c_xeCJK_math_fam_int { \use:c { sym \c_@@_math_tl } }
        \clist_concat:NNN \l_@@_tmp_clist
          \c_@@_CJK_chars_clist \c_@@_FullLeft_chars_clist
        \clist_concat:NNN \l_@@_tmp_clist
          \l_@@_tmp_clist \c_@@_FullRight_chars_clist
        \clist_map_inline:Nn \l_@@_tmp_clist
          {
            \@@_set_char_class_aux:Nnw \xeCJK_gset_mathcode:nnnn {##1}
              { \c_zero } { \c_xeCJK_math_fam_int }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_gset_mathcode:nnnn}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_gset_mathcode:nnnn #1#2#3#4
  {
    \@@_check_num_range:nnNN {#1} {#2} \l_@@_begin_int \l_@@_end_int
    \xeCJK_int_until_do:nn { \l_@@_begin_int > \l_@@_end_int }
      {
        \tex_global:D \xeCJK_xetex_mathcode:w
          \l_@@_begin_int = #3 ~ #4 \l_@@_begin_int
        \int_incr:N \l_@@_begin_int
      }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{抄录环境中的间距调整}
%
% \changes{v3.1.0}{2012/11/19}{放弃使用放缩字体大小的方式，而只采用调整间距的方式
% 与西文等宽字体对齐。并且只适用于与抄录环境下。}
% \changes{v3.2.0}{2013/04/15}{增加 \texttt{Verb} 选项。}
% \changes{v3.2.1}{2013/05/29}{调整 \texttt{Verb} 选项：在命令 \tn{verb} 里使用时，
% 不破坏标点禁则，增加值 \texttt{env+}。}
%
% \begin{macro}{Verb}
% \changes{v3.2.5}{2013/07/25}{微调定义。}
% 如果设置为 \texttt{env}，则只在 \LaTeX 的抄录环境里使用 \tn{xeCJKVerbAddon}，^^A
% 而不包括 \tn{verb}。对当前使用环境的判断基于在标准 \LaTeX 的坏境定义里使用
% \tn{begingroup} 和 \tn{endgroup} 来分组。
%    \begin{macrocode}
\int_new:N \l_@@_verb_case_int
\keys_define:nn { xeCJK / options }
  {
    Verb .choices:nn =
      { true , env+ , env , false }
      { \int_set_eq:NN \l_@@_verb_case_int \l_keys_choice_int } ,
    Verb  .default:n = { env }
  }
\cs_new_protected_nopar:Npn \@@_verb_font_hook:
  {
    \if_case:w \l_@@_verb_case_int
    \or:
      \@@_nobreak_skip_zero:
    \or:
      \int_compare:nNnTF \etex_currentgrouptype:D = \c_fourteen
        { \xeCJKVerbAddon }
        { \@@_nobreak_skip: }
    \or:
      \int_compare:nNnTF \etex_currentgrouptype:D = \c_fourteen
        { \xeCJKVerbAddon }
        { \@@_nobreak_skip_zero: }
    \fi:
  }
\@@_after_preamble:n
  {
    \cs_set_protected_nopar:Npx \verbatim@font
      { \exp_not:o { \verbatim@font } \@@_verb_font_hook: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_nobreak_skip_zero:,\@@_nobreak_skip:}
% \changes{v3.2.8}{2013/11/16}{禁止在 \tn{verb} 中断行。}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_nobreak_skip_zero:
  {
    \@@_reset_shipout_skip:
    \cs_set_eq:NN \@@_shipout_check_for_glue: \xeCJK_check_for_glue:
    \cs_set_eq:NN \@@_shipout_boundary:w \xeCJK_CJK_and_Boundary:w
    \tl_put_right:Nn \l_@@_reset_shipout_skip_hook_tl
      {
        \cs_set_eq:NN \xeCJK_check_for_glue: \@@_shipout_check_for_glue:
        \cs_set_eq:NN \xeCJK_CJK_and_Boundary:w \@@_shipout_boundary:w
      }
    \xeCJK_cs_clear:N \CJKglue
    \xeCJK_cs_clear:N \CJKecglue
    \xeCJK_cs_clear:N \xeCJK_check_for_glue:
    \cs_set_eq:NN \xeCJK_CJK_and_Boundary:w \xeCJK_class_group_end:
    \cs_set_eq:NN \@@_punct_hskip:n \@@_nobreak_hskip:n
    \cs_set_eq:NN \@@_punct_breakable_kern:n \@@_nobreak_hskip:n
  }
\cs_new_protected_nopar:Npn \@@_nobreak_skip:
  {
    \@@_reset_shipout_skip:
    \xeCJK_glue_to_skip:nN { \CJKglue } \l_@@_ccglue_skip
    \skip_if_eq:nnTF { \l_@@_ccglue_skip } { \c_zero_skip }
      { \xeCJK_cs_clear:N \CJKglue }
      { \cs_set_eq:NN \CJKglue \@@_nobreak_ccglue: }
    \xeCJK_glue_to_skip:nN { \CJKecglue } \l_@@_ecglue_skip
    \skip_if_eq:nnTF { \l_@@_ecglue_skip } { \c_zero_skip }
      { \xeCJK_cs_clear:N \CJKecglue }
      { \cs_set_eq:NN \CJKecglue \@@_nobreak_ecglue: }
    \cs_set_eq:NN \@@_punct_hskip:n \@@_nobreak_hskip:n
    \cs_set_eq:NN \@@_punct_breakable_kern:n \@@_nobreak_hskip:n
  }
\cs_new_protected_nopar:Npn \@@_nobreak_ccglue:
  { \xeCJK_no_break: \skip_horizontal:N \l_@@_ccglue_skip }
\cs_new_protected_nopar:Npn \@@_nobreak_ecglue:
  { \xeCJK_no_break: \skip_horizontal:N \l_@@_ecglue_skip }
\cs_new_protected_nopar:Npn \@@_nobreak_hskip:n
  { \xeCJK_no_break: \skip_horizontal:n }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_reset_shipout_skip:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_reset_shipout_skip:
  {
    \cs_set_eq:NN \@@_shipout_CJKglue:   \CJKglue
    \cs_set_eq:NN \@@_shipout_CJKecglue: \CJKecglue
    \cs_set_eq:NN \@@_shipout_punct_hskip:n \@@_punct_hskip:n
    \cs_set_eq:NN
      \@@_shipout_punct_breakable_kern:n \@@_punct_breakable_kern:n
    \tl_set:Nx \l_@@_off_verb_addon_tl
      {
        \bool_if:NTF \l_@@_xecglue_bool
          { \keys_set:nn { xeCJK / options } { xCJKecglue = true } }
          { \keys_set:nn { xeCJK / options } { xCJKecglue = false } }
        \exp_not:n
          {
            \cs_set_eq:NN \CJKglue \@@_shipout_CJKglue:
            \cs_set_eq:NN \CJKecglue \@@_shipout_CJKecglue:
            \cs_set_eq:NN \@@_punct_hskip:n \@@_shipout_punct_hskip:n
            \cs_set_eq:NN
              \@@_punct_breakable_kern:n \@@_shipout_punct_breakable_kern:n
            \l_@@_reset_shipout_skip_hook_tl
          }
      }
    \xeCJK_add_to_shipout:n { \l_@@_off_verb_addon_tl }
    \keys_set:nn { xeCJK / options } { xCJKecglue = false }
  }
\tl_new:N \l_@@_reset_shipout_skip_hook_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKOffVerbAddon,\xeCJKVerbAddon}
% \changes{v3.1.0}{2012/11/19}{新增 \tn{xeCJKVerbAddon} 用于抄录环境中的间距调整。}
% \changes{v3.2.3}{2013/06/04}
% {新增 \tn{xeCJKOffVerbAddon} 用于局部取消 \tn{xeCJKOffVerbAddon} 的影响；并解决
% 跨页使用时影响到页眉页脚的问题。}
% \changes{v3.2.5}{2013/07/13}{禁止自动换行，与西文一致。}
% \changes{v3.2.8}{2013/11/16}{增加是否是等宽字体的判断。}
% \tn{xeCJKVerbAddon} 进行了比较大的调整，应该只在分组环境里使用。为了方便调整间距
% 以利于对齐，这里只把字符分成了两类，并且在 CJK 类与边界（空格）之间也插入
% \tn{CJKecglue}。以字母“M”的宽度是否等于 \tn{fontdimen2} 来判断当前字体是否是
% 等宽字体。如果不是等宽字体，则设置间距为零或正文间距。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKVerbAddon { }
  {
    \int_compare:nNnF \etex_currentgrouplevel:D = \c_zero
      {
        \bool_if:NF \l_@@_listings_env_bool
          {
            \dim_compare:nNnTF
              { \tex_fontdimen:D \c_two \tex_font:D } =
              { \etex_fontcharwd:D \tex_font:D \c_@@_mono_letter_int }
              {
                \@@_set_verb_exspace:
                \@@_verb_addon:
              }
              {
                \int_if_odd:nTF { \l_@@_verb_case_int }
                  { \@@_nobreak_skip_zero: }
                  { \@@_nobreak_skip: }
              }
          }
      }
  }
\int_const:Nn \c_@@_mono_letter_int { 77 }
\bool_new:N \l_@@_listings_env_bool
\NewDocumentCommand \xeCJKOffVerbAddon { }
  { \tl_use:N \l_@@_off_verb_addon_tl }
\tl_new:N \l_@@_off_verb_addon_tl
\cs_new_protected_nopar:Npn \@@_verb_addon:
  {
    \bool_if:NF \l_@@_verb_addon_bool
      {
        \bool_set_true:N \l_@@_verb_addon_bool
        \@@_set_char_class_eq:nn { FullLeft }    { CJK }
        \@@_set_char_class_eq:nn { FullRight }   { CJK }
        \@@_set_char_class_eq:nn { HalfLeft }    { Default }
        \@@_set_char_class_eq:nn { HalfRight }   { Default }
        \@@_set_char_class_eq:nn { NormalSpace } { Default }
        \cs_set_eq:NN \@@_shipout_CJKglue:   \CJKglue
        \cs_set_eq:NN \@@_shipout_CJKecglue: \CJKecglue
        \cs_set_eq:NN \@@_shipout_check_for_glue: \xeCJK_check_for_glue:
        \cs_set_eq:NN \@@_shipout_boundary:w \xeCJK_CJK_and_Boundary:w
        \cs_set_protected_nopar:Npx \xeCJKOffVerbAddon
          {
            \@@_reset_char_class:n { FullLeft }
            \@@_reset_char_class:n { FullRight }
            \@@_reset_char_class:n { HalfLeft }
            \@@_reset_char_class:n { HalfLeft }
            \@@_reset_char_class:n { NormalSpace }
            \bool_if:NTF \l_@@_xecglue_bool
              { \keys_set:nn { xeCJK / options } { xCJKecglue = true } }
              { \keys_set:nn { xeCJK / options } { xCJKecglue = false } }
            \exp_not:n
              {
                \cs_set_eq:NN \CJKglue   \@@_shipout_CJKglue:
                \cs_set_eq:NN \CJKecglue \@@_shipout_CJKecglue:
                \cs_set_eq:NN \xeCJK_check_for_glue: \@@_shipout_check_for_glue:
                \cs_set_eq:NN \xeCJK_CJK_and_Boundary:w \@@_shipout_boundary:w
              }
          }
        \xeCJK_add_to_shipout:n { \xeCJKOffVerbAddon }
        \keys_set:nn { xeCJK / options } { xCJKecglue = false }
      }
    \skip_if_eq:nnTF { \l_@@_verb_exspace_skip } { \c_zero_skip }
      {
        \xeCJK_cs_clear:N \CJKglue
        \xeCJK_cs_clear:N \CJKecglue
      }
      {
        \skip_set_eq:NN \l_@@_ccglue_skip \l_@@_verb_exspace_skip
        \skip_set:Nn \l_@@_ecglue_skip { .5 \l_@@_verb_exspace_skip }
        \cs_set_eq:NN \CJKglue   \@@_nobreak_ccglue:
        \cs_set_eq:NN \CJKecglue \@@_nobreak_ecglue:
      }
    \cs_set_eq:NN \xeCJK_check_for_glue: \CJKecglue
    \cs_set_eq:NN \xeCJK_CJK_and_Boundary:w \@@_verb_CJK_and_Boundary:w
  }
\cs_new_protected_nopar:Npn \@@_verb_CJK_and_Boundary:w
  { \xeCJK_class_group_end: \CJKecglue }
\cs_new_protected_nopar:Npn \@@_reset_char_class:n #1
  {
    \int_set:Nn \l_@@_tmp_int { \xeCJK_class_num:n {#1} }
    \clist_map_inline:cn { c_@@_#1_chars_clist }
      { \XeTeXcharclass ##1 = \l_@@_tmp_int }
  }
\bool_new:N \l_@@_verb_addon_bool
\cs_new_eq:NN \CJKfixedspacing \xeCJKVerbAddon
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_set_verb_exspace:}
% \changes{v3.1.1}{2012/12/08}{调整间距的计算方法。}
% \changes{v3.2.4}{2013/06/29}{当计算得出的间距为负时，缩小 CJK 字体。}
% 在抄录环境中，CJK 文字之间的间距为当前西文字体两个空格的宽度与当前字体大小之差，
% 而与西文和空格的间距为 CJK 文字之间的间距的一半。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_set_verb_exspace:
  {
    \tl_if_exist:cTF { xeCJK/verb/\CJK@family/\curr@fontshape/\f@size }
      {
        \skip_set:Nn \l_@@_verb_exspace_skip
          { \use:c { xeCJK/verb/\CJK@family/\curr@fontshape/\f@size } }
      }
      {
        \tl_set:Nx \l_@@_current_coor_tl { \CJK@family/\curr@fontshape }
        \prop_get:NVNTF \g_@@_scale_family_prop
          \l_@@_current_coor_tl \l_xeCJK_family_tl
          {
            \xeCJK_switch_family:n { \l_xeCJK_family_tl }
            \skip_zero:N \l_@@_verb_exspace_skip
          }
          {
            \group_begin: \xeCJK_select_font: \exp_after:wN \group_end:
            \exp_after:wN \@@_set_verb_exspace:n
            \exp_after:wN { \dim_use:N \etex_fontcharwd:D \tex_font:D "4E00 }
          }
      }
  }
\skip_new:N \l_@@_verb_exspace_skip
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_set_verb_exspace:n}
% 当两个西文空格的宽度小于一个 CJK 文字的宽度时，对目前使用的 CJK 字体进行适当缩小。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_set_verb_exspace:n #1
  {
    \skip_set:Nn \l_@@_verb_exspace_skip
      { \c_two \tex_fontdimen:D \c_two \tex_font:D - #1 }
    \dim_compare:nNnTF \l_@@_verb_exspace_skip < \c_zero_dim
      {
        \skip_zero:N \l_@@_verb_exspace_skip
        \use:x
          {
            \@@_set_verb_scale:nn
              { \dim_to_fp:n { \c_two \tex_fontdimen:D \c_two \tex_font:D } }
              { \dim_to_fp:n {#1} }
          }
      }
      {
        \tl_const:cx { xeCJK/verb/\CJK@family/\curr@fontshape/\f@size }
          { \skip_use:N \l_@@_verb_exspace_skip }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_set_verb_scale:nn}
% 缩小 CJK 字体，并保存相关信息。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_set_verb_scale:nn #1#2
  {
    \fp_set:Nn \l_@@_scale_factor_fp { #1 / #2 }
    \@@_warning:nxx { scale-factor }
      { \fp_eval:n { trunc ( \l_@@_scale_factor_fp , 4 ) } }
      { \fp_eval:n {  ceil ( #2 / #1 , 4 ) } }
    \xeCJK_add_font_features:Nnx \c_true_bool
      { } { Scale = { \fp_use:N \l_@@_scale_factor_fp } }
    \prop_gput:NVV \g_@@_scale_family_prop
      \l_@@_current_coor_tl \l_xeCJK_family_tl
  }
\@@_msg_new:nn { scale-factor }
  {
    `\token_to_str:N \xeCJKVerbAddon'~may~not~work~properly.\\\\
    You~may~set~`Scale=#1'~to~CJKfamily~
    `\@@_msg_family_map:n { \l_xeCJK_family_tl }',\\
    or~set~`Scale=#2'~to~family~
    `\str_if_eq_x:nnTF \f@family \ttdefault
      { \token_to_str:N \ttdefault } { \f@family }'.
  }
\fp_new:N \l_@@_scale_factor_fp
\prop_new:N \g_@@_scale_family_prop
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_visible_space:}
% \changes{v3.2.5}{2013/07/13}{可视空格考虑传统 \TeX 字体的情况。}
% 如果文档不使用 \texttt{EU1} 作为默认字体编码，那么默认的打字机字体族很可能是
% 传统的 \TeX 字体，这时可视空格按照 \texttt{OT1} 编码传统一般就是字体中的 |\char32|。
% 这里加入 \cs{scan_stop:} 的目的是强制发生状态转移。这样当空格出现在 CJK 文字
% 后面时，使字体回到西文，保证在当前西文字体而不是在 CJK 字体中检查有没有 |U+2423|。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_visible_space:
  {
    \bool_if:NT \l_@@_CJK_group_bool { \scan_stop: }
    \xeCJK_glyph_if_exist:NTF { ^^^^2423 }
      { ^^^^2423 }
      {
        \int_compare:nNnTF { \XeTeXfonttype \tex_font:D } = \c_zero
          {
            \str_if_eq_x:nnTF { \f@family } { \ttdefault }
              { \c_catcode_other_space_tl }
              { \textvisiblespace }
          }
          { \xeCJK_visible_space_fallback: }
      }
  }
\AtEndOfPackage
  { \cs_gset_eq:NN \fontspec_visible_space: \xeCJK_visible_space: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_visible_space_fallback:}
% \changes{v3.1.0}{2012/11/19}
% {调整 \pkg{fontspec} 的后备可视空格符号，以便于使用时对齐。}
% \pkg{fontspec} 使用 |lmtt| 字体中的可视空格符号（|U+2423|）作为当前字体中相应符号
% 的后备。但是 |lmtt| 的字体大小未必与当前字体匹配。因此，我们在这里做一些调整，以
% 保证使用后备可视空格符号时，也能保证对齐。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_visible_space_fallback:
  { {
      \cs_if_exist_use:cF { xeCJK/space/\curr@fontshape/\f@size }
        { \xeCJK_set_visible_space_font: }
      ^^^^2423
  } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_set_visible_space_font:}
% 当前字体空格的宽度与后备字体 |lmtt| 不一样时，就对 \tn{textvisiblespace} 的字体尺寸
% 按相应的比例放缩。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_set_visible_space_font:
  {
    \tl_set:Nx \l_@@_current_coor_tl { xeCJK/space/\curr@fontshape/\f@size }
    \exp_after:wN \@@_set_visible_space_size:n
    \exp_after:wN { \dim_use:N \tex_fontdimen:D \c_two \tex_font:D }
    \xeCJK_font_gset_to_current:c { \l_@@_current_coor_tl }
  }
\cs_new_protected_nopar:Npn \@@_set_visible_space_size:n #1
  {
    \fontencoding { \g_fontspec_encoding_tl }
    \tl_set:Nx \f@family { lmtt }
    \selectfont
    \dim_compare:nNnF {#1} = { \tex_fontdimen:D \c_two \tex_font:D }
      {
        \fontsize
          {
            \dim_eval:n
              {
                \f@size pt *
                \dim_ratio:nn {#1} { \tex_fontdimen:D \c_two \tex_font:D }
              }
          }
          { \f@baselineskip }
        \selectfont
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{\pkg{xeCJK} 其它选项}
%
% \begin{macro}{LocalConfig}
% \changes{v3.1.0}{2012/11/20}{增加 \texttt{LocalConfig} 选项用于载入本地配置文件。}
% 声明载入本地配置文件的选项。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    LocalConfig .choice: ,
    LocalConfig / false   .code:n =
      { \bool_gset_false:N \g_@@_config_bool } ,
    LocalConfig / true    .code:n =
      {
        \bool_gset_true:N \g_@@_config_bool
        \tl_gset:Nn \g_@@_config_name_tl { xeCJK }
      } ,
    LocalConfig / unknown .code:n =
      {
        \bool_gset_true:N \g_@@_config_bool
        \tl_gset:Nx \g_@@_config_name_tl { xeCJK - \l_keys_value_tl }
      } ,
    LocalConfig        .default:n = { true }
  }
\tl_new:N \g_@@_config_name_tl
\bool_new:N \g_@@_config_bool
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{CJKnumber,indentfirst}
% \changes{v3.2.11}{2014/03/14}{放弃 \texttt{indentfirst} 和 \texttt{CJKnumber} 选项。}
% \texttt{CJKnumber} 和 \texttt{indentfirst} 是过时选项。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    CJKnumber         .code:n =
      { \@@_warning:nxx { option-deprecated } { \l_keys_key_tl } { CJKnumb } } ,
    indentfirst       .code:n =
      { \@@_warning:nxx { option-deprecated } { \l_keys_key_tl } { indentfirst } } ,
    normalindentfirst .code:n =
      { \@@_warning:nxx { option-deprecated } { \l_keys_key_tl } { } }
  }
\@@_msg_new:nn { option-deprecated }
  {
    The~`#1'~option~is~deprecated.\\
    \tl_if_empty:nF {#2}
      { You~may~load~the~package~`#2'~after~xeCJK~to~use~its~function.\\ }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{quiet,silent}
% 将调用 \pkg{xeCJK} 时使用的未知的选项传递给 \pkg{fontspec} 宏包。
% 对 \pkg{fontspec} 的 |quiet| 和 |silent| 选项进行修改，使其适用于 \pkg{xeCJK}。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    quiet .code:n =
      {
        \msg_redirect_module:nnn { xeCJK } { warning } { info }
        \msg_redirect_module:nnn { xeCJK } { info }    { none }
        \xeCJK_if_package_loaded:nF { fontspec }
          { \PassOptionsToPackage { quiet } { fontspec } }
      } ,
    silent .code:n =
      {
        \msg_redirect_module:nnn { xeCJK } { warning } { none }
        \msg_redirect_module:nnn { xeCJK } { info }    { none }
        \xeCJK_if_package_loaded:nF { fontspec }
          { \PassOptionsToPackage { silent } { fontspec } }
      } ,
    unknown .code:n =
      {
        \xeCJK_if_package_loaded:nTF { fontspec }
          { \@@_error:nx { key-unknown } { \l_keys_key_tl } }
          { \PassOptionsToPackage { \l_keys_key_tl } { fontspec } }
      }
  }
\@@_msg_new:nn { key-unknown }
  {
    Sorry,~but~\l__keys_module_tl \ does~not~have~a~key~called~`#1'.\\\\
    The~key~`#1'~is~being~ignored.
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{\pkg{xeCJK} 初始化设置}
%
% \begin{macro}[internal]{\CJKsymbol, \CJKpunctsymbol}
%    \begin{macrocode}
\cs_new_nopar:Npn \CJKsymbol      #1 {#1}
\cs_new_nopar:Npn \CJKpunctsymbol #1 {#1}
%    \end{macrocode}
% \end{macro}
%
% \pkg{xeCJK} 宏包的初始化设置。
%
%    \begin{macrocode}
\keys_set:nn { xeCJK / options }
  {
    CJKglue         = { \skip_horizontal:n { \c_zero_dim plus 0.08 \tex_baselineskip:D } } ,
    CJKecglue       = { ~ } ,
    xCJKecglue      = false ,
    CheckSingle     = false ,
    PlainEquation   = false ,
    CheckFullRight  = false ,
    CJKspace        = false ,
    CJKmath         = false ,
    xeCJKactive     = true  ,
    LocalConfig     = true  ,
    LoadFandol      = true  ,
    RubberPunctSkip = true  ,
    Verb            = env   ,
    EmboldenFactor  = 4     ,
    SlantFactor     = 0.167 ,
    PunctStyle      = quanjiao ,
    NewLineCS       = { \par \[ } ,
    EnvCS           = { \begin \end } ,
    NoBreakCS       = { \footnote \footnotemark \nobreak } ,
    KaiMingPunct    = { ^^^^3002 ^^^^ff0e ^^^^ff1f ^^^^ff01 } ,
    LongPunct       = { ^^^^2014 ^^^^2015 ^^^^2500 ^^^^2025 ^^^^2026 } ,
    MiddlePunct     = { ^^^^2014 ^^^^2015 ^^^^2027 ^^^^2500 ^^^^00b7 ^^^^30fb ^^^^ff65 } ,
    AllowBreakBetweenPuncts = false
  }
\defaultCJKfontfeatures { Script = CJK }
%    \end{macrocode}
%
% 执行宏包选项，并载入 \pkg{fontspec} 宏包和 \pkg{xunicode-addon}。
%    \begin{macrocode}
\ProcessKeysOptions { xeCJK / options }
\RequirePackage { fontspec } [ 2012/05/01 ]
\RequirePackage { xunicode-addon }
%    \end{macrocode}
%
% \begin{macro}[internal,var]{\c_@@_encoding_tl}
% 保存 \pkg{fontspec} 声明字体时使用的字体编码。
%    \begin{macrocode}
\tl_const:Nx \c_@@_encoding_tl { \g_fontspec_encoding_tl }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.1.0}{2012/11/21}{改用 \pkg{indentfirst} 宏包处理缩进的问题。}
%
% 对不能通过 \tn{xeCJKsetup} 设置的选项给出警告。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    LocalConfig .code:n =
      { \@@_warning:nx { option-invalid } { \l_keys_key_tl } }
  }
\@@_msg_new:nn { option-invalid }
  {
    The~`#1'~option~only~can~be~set~in~the~optional~argument~to~the\\
    \token_to_str:N \usepackage \ command~when~xeCJK~is~being~loaded.\\\\
    Please~do~not~set~it~via~the~\token_to_str:N \xeCJKsetup \ command.
  }
%    \end{macrocode}
%
% \begin{macro}[var]{\CJKrmdefault,\CJKsfdefault,\CJKttdefault,\CJKfamilydefault}
%    \begin{macrocode}
\tl_if_exist:NF \CJKrmdefault { \tl_gset:Nn \CJKrmdefault { rm } }
\tl_if_exist:NF \CJKsfdefault { \tl_gset:Nn \CJKsfdefault { sf } }
\tl_if_exist:NF \CJKttdefault { \tl_gset:Nn \CJKttdefault { tt } }
\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
      {
        \tl_if_exist:NTF \CJKfamilydefault
          { \exp_not:V \CJKfamilydefault }
          { \exp_not:N \CJKrmdefault }
      }
  }
\tl_gset_eq:NN \CJKfamilydefault \l_@@_family_default_init_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKsetup}
% 在导言区或文档中设置 \pkg{xeCJK} 的接口。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKsetup { +m }
  {
    \keys_set:nn { xeCJK / options } {#1}
    \tex_ignorespaces:D
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJKsetemboldenfactor, \xeCJKsetslantfactor}
%    \begin{macrocode}
\NewDocumentCommand \xeCJKsetemboldenfactor { m }
  { \xeCJKsetup { EmboldenFactor = {#1} } }
\NewDocumentCommand \xeCJKsetslantfactor { m }
  { \xeCJKsetup { SlantFactor = {#1} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\punctstyle, \xeCJKplainchr}
%    \begin{macrocode}
\NewDocumentCommand \punctstyle { m } { \xeCJKsetup { PunctStyle = {#1} } }
\NewDocumentCommand \xeCJKplainchr { } { \xeCJKsetup { PunctStyle = plain } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\CJKsetecglue}
%    \begin{macrocode}
\NewDocumentCommand \CJKsetecglue { m } { \xeCJKsetup { CJKecglue = {#1} } }
\cs_new_eq:NN \xeCJKsetecglue \CJKsetecglue
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\CJKspace,\CJKnospace}
%    \begin{macrocode}
\NewDocumentCommand \CJKspace   { } { \xeCJKsetup { CJKspace = true } }
\NewDocumentCommand \CJKnospace { } { \xeCJKsetup { CJKspace = false } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJKallowbreakbetweenpuncts, \xeCJKnobreakbetweenpuncts}
%    \begin{macrocode}
\NewDocumentCommand \xeCJKallowbreakbetweenpuncts { }
  { \xeCJKsetup { AllowBreakBetweenPuncts = true } }
\NewDocumentCommand \xeCJKnobreakbetweenpuncts { }
  { \xeCJKsetup { AllowBreakBetweenPuncts = false } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJKenablefallback, \xeCJKdisablefallback}
%    \begin{macrocode}
\NewDocumentCommand \xeCJKenablefallback { }
  { \xeCJKsetup { AutoFallBack = true } }
\NewDocumentCommand \xeCJKdisablefallback { }
  { \xeCJKsetup { AutoFallBack = false } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJKsetcharclass}
%    \begin{macrocode}
\NewDocumentCommand \xeCJKsetcharclass { m m m }
  {
    \xeCJK_set_char_class:nnn {#1} {#2} {#3}
    \xeCJKResetPunctClass
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{兼容性修补}
%
% \begin{macro}[internal]{\hbar}
% \changes{v3.2.16}{2014/11/20}{修复 \tn{hbar}。}
% \pkg{fontspec} 会设置 operators 数学字体族（|\fam0|）为 \texttt{EU1} 编码的
% \tn{rmdefault} 字体。这导致 \LaTeXe{} 定义的 \tn{hbar} 只显示为 $h$。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_fix_hbar:
  {
    \cs_if_free:NF \symlegacymaths
      {
        \group_begin:
          \cs_set_nopar:Npn \@@_tmp:w
            { { \mathchar '26 \mkern -9mu h } }
        \exp_after:wN \group_end:
        \if_meaning:w \@@_tmp:w \hbar
          \cs_set_protected_nopar:Npx \hbar
            { {
              \mathchar
                \int_eval:n { \symlegacymaths * \c_two_hundred_fifty_six + '26 } ~
              \mkern -9mu h
            } }
        \fi:
      }
  }
\cs_if_exist:NTF \fontspec_maybe_setup_maths:
  {
    \cs_gset_protected_nopar:Npx \fontspec_maybe_setup_maths:
      {
        \exp_not:o { \fontspec_maybe_setup_maths: }
        \xeCJK_fix_hbar:
      }
  }
  { \AtBeginDocument { \xeCJK_fix_hbar: } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_update_url_font:,\Url@MathSetup}
% \changes{v3.2.7}{2013/11/09}{使通过 \tn{UrlFont} 等命令设置的 CJK 字体生效。}
% 使通过 \tn{urlstyle} 或者 \tn{UrlFont} 设置的路径中使用的 CJK 字体生效。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_update_url_font:
  {
    \group_begin: \xeCJK_select_font: \exp_after:wN \group_end:
    \exp_after:wN \tex_textfont:D \exp_after:wN \c_xeCJK_math_fam_int
    \tex_the:D \tex_font:D
  }
\@@_after_end_preamble:n
  {
    \bool_if:nT { \g_@@_math_bool && \cs_if_exist_p:N \Url@MathSetup }
      { \tl_put_right:Nn \Url@MathSetup { \@@_update_url_font: } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\fontspec_setup_maths:,\mathrm}
% \changes{v3.2.6}{2013/08/02}{为 \tn{mathrm} 减少一个可能的数学字体族。}
% 如果没有设置 \tn{setboldmathrm}，即 \cs{g_fontspec_bfmathrm_tl} 为空，那么
% \tn{mathrm} 的字体实际与 \texttt{operators} 字体族完全一致。这时候应该通过
% \tn{DeclareSymbolFontAlphabet} 来定义 \tn{mathrm}，避免使用它的时候再声明
% 一个重复的数学字体族。\pkg{fontspec} v2.4a 已经正确定义了 \tn{mathrm}。
%    \begin{macrocode}
\@ifpackagelater { fontspec } { 2014/06/21 } { }
  {
    \cs_gset_protected_nopar:Npx \fontspec_setup_maths:
      {
        \exp_not:o
          {
            \fontspec_setup_maths:
            \bool_if:nT
              {
                \tl_if_empty_p:N \g__fontspec_bfmathrm_tl ||
                \tl_if_empty_p:N \g_fontspec_bfmathrm_tl
              }
              { \DeclareSymbolFontAlphabet \mathrm { operators } }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\(,\),\math,\endmath,\ensuremath,\@@_math_robust:N}
% \changes{v3.2.5}{2013/07/25}
% {解决汉字后紧跟 \tn{(}\texttt{...}\tn{)} 形式的行内数学公式时，不能加入间距的问题。}
% \changes{v3.2.6}{2013/08/03}{考虑 \pkg{ulem} 对 \tn{MakeRobust} 的不当定义。}
% \changes{v3.2.6}{2013/08/03}{考虑 \tn{math} 和 \tn{ensuremath}。}
% \tn{(} 的在 \LaTeXe 中的定义是
% \begin{verbatim}
%   \def\({\relax\ifmmode\@badmath\else$\fi}
% \end{verbatim}
% 这个定义最开始的 \tn{relax} 是为了防止 \tn{(} 出现在表格单元格的开始位置时，模式
% 判断不正确（因为 \TeX 会先看单元格中第一个不可展的非空格记号是否是 \tn{omit} 或
% \tn{noalign}）。但是它会造成一个边界，使 \pkg{xeCJK} 不能看到 \tn{relax} 后面出现的
% |$|，从而不能加入间距\footnote{\url{http://tex.stackexchange.com/q/124773}}。使用
% \hologo{eTeX} 的 \tn{protected} 来定义它，可以不需要 \tn{relax}，或者将 \tn{relax}
% 改成 \cs{scan_align_safe_stop:}，都可以避免这些情况。同时 \pkg{fixltx2e} 中还使用了
% |\MakeRobust\(|，我们需要小心处理。另外 \pkg{ulem} 也定义了一个 \tn{MakeRobust}，
% 如果它被放在 \pkg{fixltx2e} 之前载入，那么 \pkg{fixltx2e} 的定义就会失效（因为
% \pkg{fixltx2e} 使用 \tn{providecommand}|*| 来定义 \tn{MakeRobust}）。但是 \pkg{ulem}
% 的定义并不完全正确，没有考虑 \TeX 不会略去控制符号后面的空格的情况。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_math_robust:N #1
  { \exp_args:NNc \@@_math_robust_aux:NN #1 { \cs_to_str:N #1 ~ } }
\cs_new_protected_nopar:Npn \@@_math_robust_aux:NN #1#2
  {
    \exp_args:Nx \str_case:nnTF { \token_get_replacement_spec:N #1 }
      {
        { \x@protect #1 \protect #2 } { }
        { \protect #2 } { }
      }
      { \@@_math_robust:NN #1#2 }
      { \@@_math_robust:NN #1#1 }
  }
\cs_new_protected_nopar:Npn \@@_math_robust:NN #1#2
  {
    \str_if_eq_x:nnTF { \token_get_arg_spec:N #2 } { }
      {
        \exp_args:No \tl_if_head_eq_meaning:nNTF {#2} \scan_stop:
          {
            \cs_gset_protected_nopar:Npx #1
              { \scan_align_safe_stop: \tl_tail:N #2 }
          }
          {
            \cs_if_eq:NNTF #1 \ensuremath
              {
                \cs_gset_protected_nopar:Npx #1
                  { \scan_align_safe_stop: \exp_not:o {#2} }
              }
              {
                \@@_warning:nxx { robust-failure }
                  { \token_to_str:N #1 } { \token_to_meaning:N #2 }
              }
          }
      }
      {
        \@@_warning:nxx { robust-failure }
          { \token_to_str:N #1 } { \token_to_meaning:N #2 }
      }
  }
\@@_msg_new:nnn { robust-failure }
  { xeCJK~can~not~make~`#1'~robust. }
  {
    The~current~meaning~of~`#1'~is:\\
    \iow_indent:n {#2}
  }
\@@_math_robust:N \(
\@@_math_robust:N \)
\@@_math_robust:N \math
\@@_math_robust:N \endmath
\@@_math_robust:N \ensuremath
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\[,\]}
% \changes{v3.2.5}{2013/07/25}{解决 \pkg{fixltx2e} 和 \pkg{amsthm} 的冲突。}
% 当 \pkg{amsmath} 没有在 \pkg{amsthm} 之前被调用时，\pkg{amsthm} 会展开 |\[|，
% 并用 |$| 作为参数定界记号，相关代码为
% \begin{verbatim}
%   \def\@tempa#1$#2#3\@nil{%
%     \def\[{#1$#2\def\@currenvir{displaymath}#3}%
%   }%
%   \expandafter\@tempa\[\@nil
% \end{verbatim}
% 而 \pkg{fixltx2e} 中使用了 |\MakeRobust\[|，使得将 |\[| 展开一次的内容中并
% 不直接含有 |$|，从而造成了 \texttt{Runaway argument?} 的错误。可以在 \pkg{amsthm}
% 之前引入 \pkg{amsmath}，避免出现这个错误。我们下面用 \hologo{eTeX} 的 \tn{protected}
% 来定义它。当然，如果之后只使用 \pkg{amsthm}，那么 |\[| 会被修改，将不再是^^A
% “健壮”的了。这也是上面 \cs{@@_math_robust:NN} 中还使用 \cs{scan_align_safe_stop:} 的原因。
%    \begin{macrocode}
\bool_if:nF
  {
    \xeCJK_if_package_loaded_p:n { amsmath } ||
    \xeCJK_if_package_loaded_p:n { amsthm }
  }
  {
    \@@_math_robust:N \[
    \@@_math_robust:N \]
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\nobreakspace}
% \changes{v3.1.2}{2013/01/01}
% {修正非 \tn{UTFencname} 编码下面 \pkg{xunicode} 重定义的 \tn{nobreakspace} 会失效的问题。}
% \changes{v3.2.5}{2013/07/18}{恢复 \tn{nobreakspace} 的原始定义。}
% 空格在 \TeX 中是特殊的记号，似乎不应该把它定义为字体中的符号（\texttt{U+00A0}）。
%    \begin{macrocode}
\UndeclareTextCommand \nobreakspace { \UTFencname }
\RenewDocumentCommand \nobreakspace { } { \leavevmode \nobreak \ }
%    \end{macrocode}
% \end{macro}
%
% 当符号命令紧跟在 CJK 字符类后面时，强制发生状态转移，使字体回到西文状态。
%    \begin{macrocode}
\AtBeginUTFCommand { \bool_if:NT \l_@@_CJK_group_bool { \scan_stop: } }
%    \end{macrocode}
%
% \changes{v3.1.1}{2012/12/13}{对于与 \pkg{xltxtra} 的冲突给出错误警告。}
% 比较老版本的 \pkg{realscripts} 定义了 \cs{dim_max:nn} 和 \cs{dim_min:nn}，这与
% 新版本的 \pkg{expl3} 冲突。
%    \begin{macrocode}
\@@_msg_new:nn { conflict-package }
  {
    The~`#1'~package~is~too~old. \\
    Please~update~an~up~to~date~version~of~it\\
    using~your~TeX~package~manager~or~from~CTAN.
  }
\xeCJK_if_package_loaded:nTF { realscripts }
  {
    \@ifpackagelater { realscripts } { 2010/10/10 } { }
      {
        \@@_error:nx { conflict-package }
          {
            \xeCJK_if_package_loaded:nTF { xltxtra }
              { xltxtra } { realscripts }
          }
      }
  }
  {
    \cs_new_eq:NN \@@_dim_max:nn \dim_max:nn
    \cs_new_eq:NN \@@_dim_min:nn \dim_min:nn
    \@@_at_end_preamble:n
      {
        \xeCJK_if_package_loaded:nT { realscripts }
          {
            \@ifpackagelater { realscripts } { 2010/10/10 } { }
              {
                \cs_gset_eq:NN \dim_max:nn \@@_dim_max:nn
                \cs_gset_eq:NN \dim_min:nn \@@_dim_min:nn
              }
          }
        \cs_undefine:N \@@_dim_max:nn
        \cs_undefine:N \@@_dim_min:nn
      }
  }
%    \end{macrocode}
%
% \begin{macro}[internal]{\fontfamily}
% \changes{v3.1.1}{2012/12/06}{修改主要 \texttt{CJK} 字体族的自动更新方式。}
% \changes{v3.1.2}{2013/01/01}{不将参数完全展开。}
% 修改 \tn{fontfamily}，使主要 |CJK| 字体族能随西文主要字体更新。
%    \begin{macrocode}
\RenewDocumentCommand \fontfamily { m }
  {
    \tl_set:Nx \f@family {#1}
    \@@_update_family:nn {#1}
      {
        { \rmdefault }     { \xeCJK_switch_family:n { \CJKrmdefault } }
        { \sfdefault }     { \xeCJK_switch_family:n { \CJKsfdefault } }
        { \ttdefault }     { \xeCJK_switch_family:n { \CJKttdefault } }
        { \familydefault } { \xeCJK_switch_family:n { \CJKfamilydefault } }
      }
  }
\cs_new_eq:NN \@@_update_family:nn \str_case:nn
%    \end{macrocode}
% \end{macro}
%
% \newbox\xeCJKtmpbox
% \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}\egroup
%
% \begin{macro}[internal]{\xeCJK@fix@penalty}
% \changes{v3.1.0}{2012/11/13}{采用通过不修改原语 \tn{/} 的方式对修复倾斜校正。}
% 对 \LaTeXe 内核中的 \tn{fix@penalty} 被用于诸如 \tn{textit} 之类的文档
% 字体转换命令的定义之中。这里对它进行补丁的目的是修复其中的倾斜校正，并使得这些
% 文档命令与紧随其后的汉字之间可以正确的插入 \tn{CJKecglue} 或者忽略其中的空格。
% 例如 \verb*|这是 \emph{强调} 文本|，第二个空格可以被忽略掉。如果使用 |xCJKecglue|
% 选项，第一个空格也可以被省略。事实上，在 \tn{sw@slant} 的定义中，\tn{@@italiccorr}
% 前面的 \tn{lastskip} 和 \tn{lastpenalty} 有四种情况，这里只对它们都为零的情况进行
% 处理。
%    \begin{macrocode}
\cs_new_eq:NN \xeCJK@fix@penalty \fix@penalty
\tl_replace_once:Nnn \xeCJK@fix@penalty { \@@italiccorr } { \xeCJK@italiccorr }
\tl_replace_once:Nnn \sw@slant          { \fix@penalty }  { \xeCJK@fix@penalty }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK@italiccorr}
% 修复倾斜校正，并处理汉字后面的空格。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK@italiccorr
  {
    \int_compare:nNnTF \XeTeXinterchartokenstate > \c_zero
      {
        \xeCJK_if_last_node:nTF { default }
          {
            \xeCJK_remove_node: \@@italiccorr
            { \xeCJK_make_node:n { default } }
          }
          {
            \xeCJK_if_last_node:nTF { CJK }
              {
                \xeCJK_remove_node: \@@italiccorr
                { \xeCJK_make_node:n { CJK } } \use:n
              }
              {
                \xeCJK_if_last_node:nTF { CJK-space }
                  {
                    \xeCJK_remove_node: \@@italiccorr
                    { \xeCJK_make_node:n { CJK-space } } \use:n
                  }
                  { \@@italiccorr \use_none:n }
              }
%    \end{macrocode}
% \cs{xeCJK_ignore_spaces:w} 里面用到 |peek| 函数来判断后面是不是空格，而此时它
% 后面还有 $4$ 个 \tn{fi} 或者 |\else...\fi| 没有被展开，将影响 |peek| 函数的
% 判断。因此我们需要用 $2^4-1=15$ 个 \cs{exp_after:wN} 来展开它们。
% 显然，这里用 \cs{exp_last_unbraced:Nf} 会比较方便，但是它会吃掉
% \verb*|\textit{...} | 等后面原来存在的空格作为完全展开的结束。要正确使用它还
% 需要另外的处理（使用 \cs{exp_stop_f:}）。
%    \begin{macrocode}
              {
                              \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
                \xeCJK_ignore_spaces:w
              }
          }
      }
      { \@@italiccorr }
  }
%    \end{macrocode}
% \end{macro}
%
% \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno
%    \begin{macrocode}
%<@@=xeCJK>
%    \end{macrocode}\egroup
%
% \begin{macro}[internal]{\@@_set_others_toks:n}
% 简单处理与同样使用 \tn{XeTeXinterchartoks} 机制的宏包的兼容问题。
%     \begin{macrocode}
\@@_after_end_preamble:n
  {
    \int_compare:nNnF
      { \c_three + \seq_count:N \g_@@_new_class_seq } = \xe@alloc@intercharclass
      {
        \int_step_inline:nnnn \c_four \c_one \xe@alloc@intercharclass
          {
            \seq_if_in:NnF \g_@@_new_class_seq {#1}
              { \@@_set_others_toks:n {#1} }
          }
      }
  }
\cs_new_protected_nopar:Npn \@@_set_others_toks:n #1
  {
    \int_set:cn { \@@_class_csname:n { Others } } {#1}
    \seq_map_inline:Nn \g_@@_CJK_class_seq
      {
        \xeCJK_copy_inter_class_toks:nnnn {##1} { Others } {##1} { NormalSpace }
        \xeCJK_copy_inter_class_toks:nnnn { Others } {##1} { NormalSpace } {##1}
        \xeCJK_app_inter_class_toks:nnx {##1} { Others }
          { \xeCJK_get_inter_class_toks:nn { Default } { Others } }
        \xeCJK_pre_inter_class_toks:nnx { Others } {##1}
          { \xeCJK_get_inter_class_toks:nn { Others } { Default } }
        \xeCJK_if_blank_x:nT
          { \xeCJK_get_inter_class_toks:nn { Others } { Boundary } }
          {
            \xeCJK_copy_inter_class_toks:nnnn
              { Others } { Boundary } { Default } { Boundary }
          }
        \xeCJK_if_blank_x:nT
          { \xeCJK_get_inter_class_toks:nn { Boundary } { Others } }
          {
            \xeCJK_copy_inter_class_toks:nnnn
              { Boundary } { Others } { Boundary } { Default }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_group_begin:,\@@_group_end:}
% 用于保护下面歧义宽度标点的分组。
%    \begin{macrocode}
\cs_new_eq:NN \@@_group_begin: \group_begin:
\cs_new_eq:NN \@@_group_end:   \group_end:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\textellipsis}
% 单独处理宽度有分歧的几个标点：包括省略号、破折号、间隔号、引号等中西文混用的
% 符号， 保证其命令形式输出的是西文字体。
%    \begin{macrocode}
\tl_map_inline:nn
  {
    \textellipsis  \textemdash     \textperiodcentered \textcentereddot
    \textquoteleft \textquoteright \textquotedblleft   \textquotedblright
    \textcdot      \textgrq        \textgrqq
  }
  {
    \AtBeginUTFCommand [#1] { \@@_group_begin: \makexeCJKinactive }
    \AtEndUTFCommand   [#1] { \@@_group_end: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\l_@@_patch_Bxii_tl,\@@_patch_Bxii:n}
% \changes{v3.2.9}{2013/12/08}
% {完整处理 \file{encguide.pdf} 的编码符号表中，与旧编码的 \texttt{U+00B7} 冲突。}
% 常被用作中文间隔号的 \texttt{U+00B7} 与 T1 等旧字体编码下定义的符号命令冲突。
% 在 \file{encguide.pdf} 的编码符号表中，如下定义有冲突。
% \begin{verbatim}
%   \DeclareTextComposite{\r}{T1}{u}{183}
%   \DeclareTextSymbol{\cyrchvcrs}{T2A}{183}
%   \DeclareTextSymbol{\cyrchldsc}{T2B}{183}
%   \DeclareTextSymbol{\cyrabhha}{T2C}{183}
%   \DeclareTextSymbol\textvibyy{T3}{183}
%   \DeclareTextComposite{\B}{T4}{t}{183}
%   \DeclareTextComposite{\`}{T5}{\ecircumflex}{183}
%   \DeclareTextDoubleComposite{\`}{T5}{\^}{e}{183}
%   \DeclareTextSymbol{\textperiodcentered}{TS1}{183}
%   \DeclareTextSymbol{\cyrchldsc}{X2}{183}
%   \DeclareTextSymbol{\textperiodcentered}{LY1}{183}
% \end{verbatim}
% LGR 编码的符号表有 \texttt{183} 号字符，但在 \file{lgrenc.def} 中未找到相应的
% 符号命令，它的输入方式为 |>`w| 或者 |\accpsilivaria{w}|。前者比较特殊，如果
% 与 \pkg{xeCJK} 一起使用，\XeTeX\ 会出现如下错误。
% \begin{verbatim}
%   ! Cannot use \XeTeXglyphbounds with grmn1000; not a native platform font.
%   \xeCJK_glyph_bounds:NN ...use:N \XeTeXglyphbounds
%                                                     #1 \XeTeXcharglyph \xeCJK_...
% \end{verbatim}
% 这个不好处理，只修改后者。
%    \begin{macrocode}
\@@_after_end_preamble:n { \l_@@_patch_Bxii_tl }
\tl_new:N \l_@@_patch_Bxii_tl
\cs_new_protected_nopar:Npn \@@_patch_Bxii:nN #1#2
  {
    \tl_put_right:Nx \l_@@_patch_Bxii_tl
      { \@@_patch_Bxii:n { #1 \token_to_str:N #2 } }
  }
\group_begin:
\cs_set:Npn \@@_tmp:w #1
  {
    \group_end:
    \cs_new_protected_nopar:Npn \@@_patch_Bxii:nNN ##1##2##3
      {
        \tl_put_right:Nx \l_@@_patch_Bxii_tl
          {
            \@@_patch_Bxii:Nnn
              #1 { ##1 \token_to_str:N ##2 } { \token_to_str:N ##3 }
          }
      }
  }
\use:n
  {
    \char_set_catcode_other:N \\
    \@@_tmp:w
  }
  { \ }
\cs_new_protected_nopar:Npn \@@_patch_Bxii:n #1
  { \cs_if_free:cF {#1} { \cs_gset_eq:cN {#1} \@@_Default_Bxii: } }
\cs_new_protected_nopar:Npn \@@_patch_Bxii:Nnn #1#2#3
  { \cs_if_free:cF {#2} { \cs_gset_eq:cN { #1#2 - #3 } \@@_Default_Bxii: } }
\group_begin:
\char_set_catcode_other:n { 183 }
\cs_new_protected_nopar:Npn \@@_Default_Bxii:
  {
    \int_compare:nNnTF \XeTeXinterchartokenstate > \c_zero
      { \@@_group_begin: \makexeCJKinactive ^^b7 \@@_group_end: }
      { ^^b7 }
  }
\group_end:
\clist_map_inline:nn
  {
    { T3  } \textvibyy ,
    { T2A } \cyrchvcrs ,
    { T2B } \cyrchldsc ,
    { T2C } \cyrabhha ,
    { X2  } \cyrchldsc ,
    { TS1 } \textperiodcentered ,
    { LY1 } \textperiodcentered
  }
  { \@@_patch_Bxii:nN #1 }
\clist_map_inline:nn
  {
    { T1  } \r u ,
    { T4  } \B t ,
    { T5  } \` \ecircumflex ,
    { LGR } \accpsilivaria w
  }
  { \@@_patch_Bxii:nNN #1 }
\tl_put_right:Nx \l_@@_patch_Bxii_tl
  {
    \@@_patch_Bxii:n
      { \token_to_str:N \T 5 \token_to_str:N \` - \token_to_str:N \^ - e }
  }
\@@_after_end_preamble:n
  {
    \xeCJK_if_package_loaded:nT { pifont }
      {
        \RenewDocumentCommand \Pifont { m }
          { \makexeCJKinactive \usefont { U } {#1} { m } { n } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% 简单处理与 \pkg{hyperref} 宏包的兼容问题。
%    \begin{macrocode}
\@@_after_end_preamble:n
  {
    \xeCJK_if_package_loaded:nT { hyperref }
      {
        \pdfstringdefDisableCommands
          {
            \@@_gobble_CJKfamily:
            \xeCJK_cs_clear:N \makexeCJKinactive
            \xeCJK_cs_clear:N \@@_group_begin:
            \xeCJK_cs_clear:N \@@_group_end:
          }
      }
  }
%    \end{macrocode}
%
% \changes{v3.1.0}{2012/11/13}{取消 \tn{cprotect} 的外部宏限制。}
% 当探测到 \pkg{cprotect} 宏包被引入时，则取消 \tn{cprotect} 宏的 \tn{outer} 定义。
%    \begin{macrocode}
\@@_after_end_preamble:n
  {
    \bool_if:nT
      { \xeCJK_if_package_loaded_p:n { cprotect } && \cs_if_exist_p:N \icprotect }
      { \exp_after:wN \tex_let:D \cs:w cprotect \cs_end: \icprotect }
  }
%    \end{macrocode}
%
% \changes{v3.2.11}{2014/03/14}{删除 \tn{xeCJKcaption}。}
%
% 由于 \pkg{xeCJK} 禁止 \pkg{CJKulem} 的载入，因此当使用 \pkg{ctex} 宏包的 |fntef|
% 选项时，就会出现 \tn{normalem} 没有定义的问题。此时改用 \pkg{xeCJKfntef} 以便
% 载入 \pkg{ulem}。
%
% 判断过于繁琐，应该在 \pkg{ctex} 包中妥善处理。这段代码应在 \pkg{ctex} 包发布
% 新版本后删去。
%    \begin{macrocode}
\cs_if_eq:NNTF \ifCTEX@fntef \tex_iftrue:D
  { \AtEndOfPackage { \RequirePackage { xeCJKfntef } } }
  {
    \@@_at_end_preamble:n
      {
        \xeCJK_if_package_loaded:nF { xeCJKfntef }
          {
            \xeCJK_if_package_loaded:nTF { CJKfntef }
              { \RequirePackage { xeCJKfntef } }
              {
                \xeCJK_if_package_loaded:nT { ulem }
                  { \RequirePackage { xeCJKfntef } }
              }
          }
      }
  }
%    \end{macrocode}
%
% 导言区末尾检测到 \pkg{listings} 时，自动载入 \pkg{xeCJK-listings}。
%    \begin{macrocode}
\@@_at_end_preamble:n
  {
    \xeCJK_if_package_loaded:nT { listings }
      { \RequirePackage { xeCJK-listings } }
  }
%    \end{macrocode}
%
% 由于 \pkg{xeCJK} 假装 \pkg{CJK} 已经被引入了，导致 \pkg{everysel} 判断错误，
% 从而给出 \tn{selectfont} 已经被修改的警告，并加入不必要的内容。需要在它判断
% 之前取消定义。
%    \begin{macrocode}
\@@_at_end_preamble:n
  {
    \xeCJK_if_package_loaded:nT { everysel }
      { \cs_undefine:c { ver@CJK . \c_@@_package_ext_tl } }
  }
%    \end{macrocode}
%
% \changes{v3.2.4}{2013/06/25}{不再使用 \texttt{CJKnumber} 选项，可以在
% \pkg{xeCJK} 之后直接使用 \pkg{CJKnumb} 宏包得到中文数字。}
%
% \begin{macro}[internal]{\CJKaddEncHook}
% 为使用 \pkg{CJKnumb} 宏包而作一些处理。另外 \pkg{CJKnumb} 使用的是传统汉字“萬”
% 和“億”，我们在这里把它们修正为简体字。
% \changes{v3.2.10}{2014/03/01}{使用 \pkg{CJKnumb} 时，让 \tn{Unicode} 有定义。}
%    \begin{macrocode}
\cs_new_protected:Npn \CJKaddEncHook #1#2
  {
    \str_if_eq:nnT {#1} { \CJK@UnicodeEnc }
      {
        \group_begin:
          \cs_set_eq:NN \Unicode \@@_calc_unicode:nn
          \cs_set_eq:NN \def \xeCJK_char_from_charcode:Nn
          #2
        \group_end:
        \tl_gset:Nn \CJK@tenthousand    { ^^^^4e07 }
        \tl_gset:Nn \CJK@hundredmillion { ^^^^4ebf }
        \tl_if_exist:NF \CJK@UnicodeEnc
          { \tl_const:Nn \CJK@UnicodeEnc { UTF8 } }
        \cs_if_exist:NF \Unicode
          { \cs_new_eq:NN \Unicode \xeCJK_unicode_char:nn }
      }
  }
\cs_new_protected_nopar:Npn \xeCJK_char_from_charcode:Nn #1#2
  {
    \group_begin:
    \char_set_lccode:nn { "4E00 } {#2}
    \tl_to_lowercase:n
      {
        \group_end:
        \tl_const:Nn #1 { ^^^^4e00 }
      }
  }
\cs_new_nopar:Npn \@@_calc_unicode:nn #1#2
  { (#1) * \c_two_hundred_fifty_six + (#2) }
\cs_new_protected_nopar:Npn \xeCJK_unicode_char:nn #1#2
  { \tex_char:D \etex_numexpr:D \@@_calc_unicode:nn {#1} {#2} \scan_stop: }
%    \end{macrocode}
% \end{macro}
%
% 最后引入本地配置文件。使用 \tn{@pushfilename} 和 \tn{@pushfilename} 是为了使
% 配置文件可以不受 \hologo{LaTeX3} 语法环境的影响。
%    \begin{macrocode}
\bool_if:NT \g_@@_config_bool
  {
    \@pushfilename
    \file_input:n { \g_@@_config_name_tl .cfg }
    \@popfilename
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \subsection{\pkg{xeCJKfntef}}
%
% \changes{v3.1.1}{2012/12/08}{增加小宏包 \pkg{xeCJKfntef}，用于处理下划线的问题。}
% \changes{v3.2.4}{2013/06/23}{修正 \pkg{xeCJKfntef} 与 \pkg{natbib} 等的冲突。}
% \changes{v3.2.14}{2014/10/31}{完善 \tn{varCJKunderline} 的实现。}
% \changes{v3.2.14}{2014/10/31}{解决下划线前后没有 \tn{CJKglue} 或 \tn{CJKecglue} 的问题。}
% \changes{v3.2.14}{2014/11/03}{\pkg{xeCJKfntef} 不再依赖 \pkg{CJKfntef}。}
% \changes{v3.2.15}{2014/11/07}{\pkg{xeCJKfntef} 增加 \texttt{hidden} 选项。}
%
%    \begin{macrocode}
%<*fntef>
%    \end{macrocode}
%
%    \begin{macrocode}
\PassOptionsToPackage { normalem } { ulem }
\DeclareOption* { \PassOptionsToPackage { \CurrentOption } { ulem } }
\ProcessOptions \scan_stop:
%    \end{macrocode}
%
%    \begin{macrocode}
\RequirePackage { xeCJK }
\RequirePackage { ulem }
\RequirePackage { environ }
%    \end{macrocode}
%
% 虽然我们不再依赖 \pkg{CJKfntef}，但基于历史原因，我们仍然载入它。
%    \begin{macrocode}
\file_if_exist:nT { CJKfntef.sty }
  { \RequirePackage { CJKfntef } }
%    \end{macrocode}
%
%    \begin{macrocode}
\addto@hook \UL@hook { \xeCJK_hook_for_ulem: }
%    \end{macrocode}
%
% \begin{macro}[internal]{\xeCJK_hook_for_ulem:}
% \changes{v3.1.0}{2012/11/16}{简化对 \pkg{ulem} 宏包的兼容补丁。}
% \changes{v3.1.1}{2012/12/08}{完全处理下划线里的标点符号的有关问题。}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_hook_for_ulem:
  {
    \bool_if:NF \l_@@_ulem_hook_used_bool
      {
        \bool_set_true:N \l_@@_ulem_hook_used_bool
        \@@_ulem_initial:
        \bool_if:NT \l_@@_ulem_subtract_bool
          {
            \xeCJK_swap_cs:NN \UL@leaders \xeCJK_ulem_leaders:
            \cs_set_eq:NN \@@_ulem_var_leaders: \xeCJK_ulem_var_leaders:
            \cs_set_eq:NN \xeCJK_ulem_right_skip: \@@_ulem_right_skip:
          }
        \bool_if:NT \l_@@_ulem_hidden_bool
          { \cs_set_eq:NN \UL@putbox \@@_ulem_hidden_box: }
        \bool_if:NTF \l_@@_ulem_skip_bool
          {
            \cs_set_eq:NN \@@_ulem_putbox: \UL@putbox
            \cs_set_eq:NN \@@_ulem_hskip_aux:n \xeCJK_ulem_hskip:n
          }
          {
            \xeCJK_swap_cs:NN \@@_punct_kern:n  \@@_ulem_punct_kern:n
            \xeCJK_swap_cs:NN \@@_punct_hskip:n \@@_ulem_punct_hskip:n
            \xeCJK_cs_clear:N \@@_ulem_skip_punct_begin:
            \xeCJK_cs_clear:N \@@_ulem_skip_punct_end:
          }
        \xeCJK_glue_to_skip:nN
          {
            \cs_set_eq:NN \  \tex_space:D
            \cs_set_eq:NN \penalty \tex_penalty:D
            \cs_set_eq:NN \hskip \skip_horizontal:N
            \CJKglue
          } \l_@@_ccglue_skip
        \xeCJK_glue_to_skip:nN
          {
            \cs_set_eq:NN \  \tex_space:D
            \cs_set_eq:NN \penalty \tex_penalty:D
            \cs_set_eq:NN \hskip \skip_horizontal:N
            \CJKecglue
          } \l_@@_ecglue_skip
        \xeCJK_glue_to_skip:nN { \xeCJK_space_glue: } \l_@@_space_skip
        \cs_set_protected_nopar:Npn \CJKglue
          { \@@_ulem_glue:n \l_@@_ccglue_skip }
        \cs_set_protected_nopar:Npn \CJKecglue
          { \@@_ulem_glue:n \l_@@_ecglue_skip }
        \cs_set_protected_nopar:Npn \xeCJK_space_glue:
          { \@@_ulem_glue:n \l_@@_space_skip }
        \keys_set:nn { xeCJK / options }
          { CheckFullRight = false , xCJKecglue = false }
        \xeCJK_ulem_detect_node:
      }
  }
\skip_new:N \l_@@_space_skip
\bool_new:N \l_@@_ulem_hook_used_bool
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\UL@word,\xeCJK_ulem_word:nw}
% 修改 \tn{UL@word}，目的是取得分组中的 \tn{UL@leadtype}，以便加入 \cs{xeCJK_ulem_right_skip:}。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_ulem_word:nw #1 ~
  {
    \exp_after:wN \UL@start #1 ~
    \exp_after:wN \if_meaning:w \exp_after:wN \UL@end #1
      \exp_after:wN \@@_ulem_end:
    \else:
      \exp_after:wN \@@_ulem_loop:nw
    \fi:
  }
\cs_new_protected_nopar:Npn \@@_ulem_end:
  {
        \c_group_end_token
      \hbox_set_end:
      \tex_unskip:D \tex_unskip:D \tex_unskip:D
      \xeCJK_ulem_right_skip:
      \xeCJK_ulem_right_node:
      \int_set:Nn \tex_spacefactor:D { \UL@spfactor }
    \c_group_end_token
  }
\cs_new_protected_nopar:Npn \@@_ulem_loop:nw
  {
    \reverse_if:N \if_mode_math:
      \reverse_if:N \if_dim:w \tex_lastskip:D = \c_zero_dim
        \skip_gset_eq:NN \UL@skip \tex_lastskip:D
        \tex_unskip:D
        \UL@stop \UL@leaders
      \fi:
    \fi:
    \xeCJK_ulem_word:nw \prg_do_nothing:
  }
\cs_set_eq:NN \UL@word \xeCJK_ulem_word:nw
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_ulem_left:, \xeCJK_ulem_detect_node:}
% 在下划线开始之前探测之前的 \texttt{node}，以便随后插入 \tn{CJKglue} 或 \tn{CJKecglue}。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_ulem_left:
  {
    \xeCJK_ulem_left_node:
    \xeCJK_make_group_tag:
  }
\cs_new_eq:NN \xeCJK_ulem_left_node: \prg_do_nothing:
\cs_new_protected_nopar:Npn \xeCJK_ulem_detect_node:
  {
    \scan_stop:
    \dim_compare:nNnTF \tex_lastkern:D = \c_zero_dim
      {
        \xeCJK_cs_clear:N \xeCJK_ulem_left_node:
        \cs_set_eq:NN \@@_ulem_hskip:n \xeCJK_ulem_hskip:n
      }
      {
        \dim_set_eq:NN \l_@@_tmp_dim \tex_lastkern:D
        \tex_unkern:D
        \dim_compare:nNnTF \tex_lastkern:D = { - \l_@@_tmp_dim }
          {
            \tex_unkern:D
            { \xeCJK_make_node:n { ulem-left } }
            \cs_set_protected_nopar:Npx \xeCJK_ulem_left_node:
              {
                \tex_kern:D - \dim_use:N \l_@@_tmp_dim \exp_stop_f:
                \tex_kern:D   \dim_use:N \l_@@_tmp_dim \exp_stop_f:
              }
            \cs_set_eq:NN \@@_ulem_hskip:n \@@_ulem_hskip_first:n
          }
          {
            \tex_kern:D \l_@@_tmp_dim
            \xeCJK_cs_clear:N \xeCJK_ulem_left_node:
            \cs_set_eq:NN \@@_ulem_hskip:n \xeCJK_ulem_hskip:n
          }
      }
  }
\xeCJK_declare_node:n { ulem-left }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_hskip_first:n, \xeCJK_ulem_hskip:n}
% 如果第一次调用的 \tn{CJKglue} 或 \tn{CJKecglue} 由下划线中的第一个文字和之前的
% 内容产生，就不用画下划线。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_hskip_first:n #1
  {
    \xeCJK_if_last_node:nTF { ulem-left }
      {
        \xeCJK_remove_node:
        \skip_horizontal:n {#1}
      }
      { \xeCJK_ulem_hskip:n {#1} }
    \cs_set_eq:NN \@@_ulem_hskip:n \xeCJK_ulem_hskip:n
  }
\cs_new_eq:NN \@@_ulem_hskip:n \@@_ulem_hskip_first:n
\cs_new_protected_nopar:Npn \xeCJK_ulem_hskip:n #1
  { { \skip_set:Nn \UL@skip {#1} \UL@leaders } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_ulem_right:, \xeCJK_ulem_right_node:}
% 在下划线最后的位置保存 \texttt{node}。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_ulem_right:
  {
    \scan_stop:
    \dim_compare:nNnTF \tex_lastkern:D = \c_zero_dim
      { \xeCJK_cs_gclear:N \xeCJK_ulem_right_node: }
      {
        \dim_compare:nNnTF \tex_lastkern:D = { 3 sp }
          { \xeCJK_cs_gclear:N \xeCJK_ulem_right_node: }
          {
            \exp_after:wN \tex_unkern:D
            \exp_after:wN \@@_ulem_right_aux:n
            \exp_after:wN { \dim_use:N \tex_lastkern:D }
          }
      }
  }
\cs_new_protected_nopar:Npn \@@_ulem_right_aux:n #1
  {
    \dim_compare:nNnTF \tex_lastkern:D = { - #1 }
      {
        \tex_unkern:D
        \cs_gset_protected_nopar:Npn \xeCJK_ulem_right_node:
          {
            \tex_kern:D - #1 \exp_stop_f:
            \tex_kern:D   #1 \exp_stop_f:
          }
        \tl_gset:Nx \UL@spfactor { \int_use:N \tex_spacefactor:D }
      }
      {
        \tex_kern:D #1 \exp_stop_f:
        \xeCJK_cs_gclear:N \xeCJK_ulem_right_node:
      }
  }
\cs_new_eq:NN \xeCJK_ulem_right_node: \prg_do_nothing:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_ulem_var_leaders:}
% 第一次画下划线时，先向右平移 \tn{CJKulineleftskip}，再画缩小了相同长度的下划线，
% 让左侧有间距。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_ulem_leaders:
  { \@@_ulem_var_leaders: }
\cs_new_protected_nopar:Npn \xeCJK_ulem_var_leaders:
  {
    \scan_stop:
    \skip_if_eq:nnF { \UL@skip } { \c_zero_skip }
      {
        \UL@leadtype \skip_horizontal:n { \UL@skip + \UL@pixel }
        \skip_horizontal:n { - \UL@pixel }
        \cs_gset_eq:NN \@@_ulem_var_leaders: \xeCJK_ulem_leaders:
      }
  }
\cs_new_eq:NN \@@_ulem_var_leaders: \xeCJK_ulem_var_leaders:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_ulem_right_skip:}
% 在下划线完全画好之后，我们检测最后的情况。用 \tn{unskip} 去掉最后一个下划线，再
% 重新画一个减少 \tn{CJKulinerightskip} 的。
%    \begin{macrocode}
\cs_new_eq:NN \xeCJK_ulem_right_skip: \prg_do_nothing:
\cs_new_protected_nopar:Npn \@@_ulem_right_skip:
  {
    \int_case:nn { \etex_lastnodetype:D }
      {
        { \c_one }      { \@@_ulem_right_skip_hbox: }
        { \c_eleven }   { \@@_ulem_right_skip_glue: }
        { \c_thirteen } { \@@_ulem_right_skip_penalty: }
      }
  }
\cs_new_protected_nopar:Npn \@@_ulem_right_skip_hbox:
  {
    \box_set_to_last:N \l_@@_tmp_box
    \int_compare:nNnTF \etex_lastnodetype:D = \c_twelve
      { \@@_ulem_right_skip_kern: }
      { \@@_ulem_right_skip_glue: }
    \box_use_clear:N \l_@@_tmp_box
  }
\cs_new_protected_nopar:Npn \@@_ulem_right_skip_kern:
  {
    \dim_set:Nn \l_@@_tmp_dim { - \box_wd:N \l_@@_tmp_box }
    \dim_compare:nNnT \tex_lastkern:D = \l_@@_tmp_dim
      {
        \tex_unkern:D
        \@@_ulem_right_skip_glue:
        \tex_kern:D \l_@@_tmp_dim
      }
  }
\cs_new_protected_nopar:Npn \@@_ulem_right_skip_glue:
  {
    \skip_if_eq:nnT { \tex_lastskip:D } { - \UL@pixel }
      {
        \tex_unskip:D
        \skip_set:Nn \l_@@_tmp_skip { \tex_lastskip:D - \UL@pixel }
        \tex_unskip:D
        \UL@leadtype \skip_horizontal:N \l_@@_tmp_skip
      }
  }
\cs_new_protected_nopar:Npn \@@_ulem_right_skip_penalty:
  {
    \int_set_eq:NN \l_@@_tmp_int \tex_lastpenalty:D
    \tex_unpenalty:D
    \int_compare:nNnT \etex_lastnodetype:D = \c_one
      { \@@_ulem_right_skip_hbox: }
    \tex_penalty:D \l_@@_tmp_int
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_hidden_box:}
% 只画线，不输出盒子。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_hidden_box:
  {
    \tl_if_empty:NF \UL@start
      {
        \box_use:N \c_@@_null_box
        \xeCJK_no_break:
        \xeCJK_ulem_hskip:n { \box_wd:N \UL@box }
        \box_use:N \c_@@_null_box
      }
  }
\box_new:N \c_@@_null_box
\hbox_gset:Nn \c_@@_null_box { }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_skip_punct_begin:,\@@_ulem_skip_punct_end:}
% 让下划线跳过标点符号的设置。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_skip_punct_begin:
  {
    \cs_set_eq:NN \UL@putbox \@@_ulem_skip_putbox:
    \cs_set_eq:NN \xeCJK_ulem_hskip:n \skip_horizontal:n
  }
\cs_new_protected_nopar:Npn \@@_ulem_skip_punct_end:
  {
    \cs_set_eq:NN \UL@putbox \@@_ulem_putbox:
    \cs_set_eq:NN \xeCJK_ulem_hskip:n \@@_ulem_hskip_aux:n
  }
\cs_new_eq:NN \@@_ulem_putbox: \UL@putbox
\cs_new_protected_nopar:Npn \@@_ulem_skip_putbox:
  {
    \tl_if_empty:NF \UL@start
      { \box_use_clear:N \UL@box }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_initial:}
% 这里的设置是为了在下划线状态下，下划线可以自动跳过全角标点符号和正确的在它们
% 前/后断行，并且与行首行末对齐。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_initial:
  {
    \@@_ulem_swap_cs:NN
    \xeCJK_FullLeft_and_Default:  \@@_ulem_FullLeft_and_Default:
    \xeCJK_FullLeft_and_CJK:      \@@_ulem_FullLeft_and_CJK:
    \xeCJK_FullRight_and_Default: \@@_ulem_FullRight_and_Default:
    \xeCJK_FullRight_and_CJK:     \@@_ulem_FullRight_and_CJK:
    \xeCJK_CJK_and_CJK:N          \@@_ulem_CJK_and_CJK:N
    \xeCJK_CJK_and_Boundary:w     \@@_ulem_CJK_and_Boundary:w
    \xeCJK@fix@penalty            \@@_ulem_fix_penalty:
    \@@_punct_breakable_kern:n       \@@_ulem_punct_breakable_kern:n
    \@@_Default_and_FullLeft_glue:N  \@@_ulem_Default_and_FullLeft_glue:N
    \@@_Default_and_FullRight_glue:N \@@_ulem_Default_and_FullRight_glue:N
    \@@_CJK_and_FullLeft_glue:N      \@@_ulem_CJK_and_FullLeft_glue:N
    \@@_CJK_and_FullRight_glue:N     \@@_ulem_CJK_and_FullRight_glue:N
    \@@_Boundary_and_FullLeft_glue:N \@@_ulem_Boundary_and_FullLeft_glue:N
    \q_recursion_tail \q_nil \q_recursion_stop
    \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
      {
        \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
          {
            \str_if_eq:nnTF {##1} {####1}
              {
                \xeCJK_inter_class_toks:nnn { CJK } { CJK/##1 }
                  { \@@_ulem_between_CJK_blocks:nnN { CJK } {##1} }
                \xeCJK_inter_class_toks:nnn { CJK/##1 } { CJK/##1 }
                  { \@@_ulem_between_CJK_blocks:nnN { CJK } {##1} }
              }
              {
                \xeCJK_inter_class_toks:nnn { CJK/##1 } { CJK/####1 }
                  { \@@_ulem_between_CJK_blocks:nnN {##1} {####1} }
              }
          }
      }
  }
\cs_new_protected_nopar:Npn \@@_ulem_swap_cs:NN #1#2
  {
    \quark_if_recursion_tail_stop:N #1
    \xeCJK_swap_cs:NN #1#2
    \@@_ulem_swap_cs:NN
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.1.2}{2012/12/27}{解决在下划线状态下使用 \tn{makebox} 时的错误。}
%
% \begin{macro}[internal]{\xeCJK_if_ulem_patch:TF}
% 在下划线状态下，\pkg{ulem} 宏包在数学模式或者盒子中使用 \tn{UL@hrest} 恢复
% \verb*|\ | 等的定义，此时不需要使用 \tn{UL@stop} 和 \tn{UL@start} 来断开下划线而
% 产生断点。
%    \begin{macrocode}
\cs_new_nopar:Npn \xeCJK_if_ulem_patch:TF
  {
    \if_meaning:w \  \LA@space
      \exp_after:wN \use_ii:nn
    \else:
      \exp_after:wN \use_i:nn
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_CJK_and_Boundary:w}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_CJK_and_Boundary:w
  {
    \xeCJK_if_ulem_patch:TF
      {
        \xeCJK_peek_catcode_ignore_spaces:NTF \c_math_toggle_token
          { }
          {
            \bool_if:NTF \l_@@_peek_ignore_spaces_bool
              {
                \xeCJK_class_group_end: \UL@stop
                \UL@start { \xeCJK_make_node:n { CJK-space } }
              }
              {
                \xeCJK_class_group_end: \UL@stop
                \UL@start { \xeCJK_make_node:n { CJK } }
              }
            \xeCJK_make_group_tag:
          }
      }
      { \@@_ulem_CJK_and_Boundary:w }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_fix_penalty:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_fix_penalty:
  {
    \xeCJK_if_ulem_patch:TF
      { \fix@penalty }
      { \@@_ulem_fix_penalty: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_CJK_and_CJK:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_CJK_and_CJK:N
  {
    \xeCJK_if_ulem_patch:TF
      {
        \xeCJK_class_group_end:
        \UL@stop \@@_ulem_ccglue: \UL@start
        \@@_ulem_class_group_begin:
        \CJKsymbol
      }
      { \@@_ulem_CJK_and_CJK:N }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_class_group_begin:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_class_group_begin:
  {
    \xeCJK_class_group_begin:
    \xeCJK_clear_Boundary_and_CJK_toks:
    \xeCJK_select_font:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_between_CJK_blocks:nnN}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_between_CJK_blocks:nnN #1#2
  {
    \xeCJK_if_ulem_patch:TF
      {
        \xeCJK_class_group_end:
        \UL@stop \@@_ulem_ccglue: \UL@start
        \xeCJK_class_group_begin:
        \xeCJK_clear_Boundary_and_CJK_toks:
        \@@_switch_font:nn {#1} {#2}
        \CJKsymbol
      }
      {
        \skip_horizontal:N \l_@@_ccglue_skip
        \@@_switch_font:nn {#1} {#2}
        \CJKsymbol
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_Default_and_FullLeft_glue:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_Default_and_FullLeft_glue:N #1
  {
    \xeCJK_if_ulem_patch:TF
      {
        \UL@stop
        \@@_ulem_skip_punct_begin:
        \@@_punct_glue:NN \c_@@_left_tl {#1}
        \@@_punct_offset:NN \c_@@_left_tl {#1}
        \UL@start
      }
      { \@@_ulem_Default_and_FullLeft_glue:N #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_Boundary_and_FullLeft_glue:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_Boundary_and_FullLeft_glue:N #1
  {
    \xeCJK_if_ulem_patch:TF
      {
        \UL@stop
        \@@_ulem_skip_punct_begin:
        \@@_punct_glue:NN \c_@@_left_tl {#1}
        \UL@start
      }
      { \@@_ulem_Boundary_and_FullLeft_glue:N #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_CJK_and_FullLeft_glue:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_CJK_and_FullLeft_glue:N #1
  {
    \xeCJK_if_ulem_patch:TF
      {
        \xeCJK_class_group_end:
        \UL@stop
        \@@_ulem_skip_punct_begin:
        \@@_ulem_ccglue:
        \@@_punct_glue:NN \c_@@_left_tl {#1}
        \@@_punct_offset:NN \c_@@_left_tl {#1}
        \UL@start
        \@@_ulem_class_group_begin:
      }
      { \@@_ulem_CJK_and_FullLeft_glue:N #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_Default_and_FullRight_glue:N}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_Default_and_FullRight_glue:N #1
  {
    \xeCJK_if_ulem_patch:TF
      {
        \UL@stop
        \@@_ulem_skip_punct_begin:
        \@@_punct_if_long:NTF {#1}
          { \@@_ulem_ccglue: }
          {
            \@@_punct_if_middle:NTF {#1}
              {
                \xeCJK_no_break:
                \@@_punct_glue:NN \c_@@_right_tl {#1}
                \@@_punct_bound_rule:NN \c_@@_left_tl {#1}
              }
              { \xeCJK_no_break: }
          }
        \UL@start
      }
      { \@@_ulem_Default_and_FullRight_glue:N #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_CJK_and_FullRight_glue:N}
% \changes{v3.2.2}{2013/05/30}{修正下划线不能跳过全角右标点的问题。}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_CJK_and_FullRight_glue:N #1
  {
    \xeCJK_if_ulem_patch:TF
      {
        \xeCJK_class_group_end:
        \@@_Default_and_FullRight_glue:N {#1}
        \@@_ulem_class_group_begin:
      }
      { \@@_ulem_CJK_and_FullRight_glue:N #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_FullLeft_and_Default:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_FullLeft_and_Default:
  {
    \xeCJK_if_ulem_patch:TF
      {
        \@@_punct_if_middle:NTF \g_@@_last_punct_tl
          {
            \xeCJK_get_punct_bounds:NN \c_@@_left_tl \g_@@_last_punct_tl
            \@@_punct_bound_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
            \xeCJK_class_group_end: \UL@stop \xeCJK_no_break:
            \@@_punct_glue:NN \c_@@_left_tl  \g_@@_last_punct_tl
          }
          { \xeCJK_class_group_end: \UL@stop }
        \@@_ulem_skip_punct_end:
        \xeCJK_no_break:
        \UL@start
      }
      { \@@_ulem_FullLeft_and_Default: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_FullLeft_and_CJK:}
% \changes{v3.2.3}{2013/06/04}
% {修正全角左标点后下划线与 \tn{CJKunderdot} 连用时结果不正常的问题。}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_FullLeft_and_CJK:
  {
    \xeCJK_if_ulem_patch:TF
      {
        \xeCJK_FullLeft_and_Default:
        \@@_ulem_class_group_begin:
      }
      { \@@_ulem_FullLeft_and_CJK: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_FullRight_and_Default:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_FullRight_and_Default:
  {
    \xeCJK_if_ulem_patch:TF
      {
        \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
        \xeCJK_class_group_end:
        \UL@stop
        \@@_punct_offset:NN \c_@@_right_tl \g_@@_last_punct_tl
        \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
        \@@_ulem_skip_punct_end:
        \UL@start
      }
      { \@@_ulem_FullRight_and_Default: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_FullRight_and_CJK:}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_FullRight_and_CJK:
  {
    \xeCJK_if_ulem_patch:TF
      {
        \@@_punct_rule:NN \c_@@_right_tl \g_@@_last_punct_tl
        \xeCJK_class_group_end:
        \UL@stop
        \@@_punct_offset:NN \c_@@_right_tl \g_@@_last_punct_tl
        \@@_punct_glue:NN \c_@@_right_tl \g_@@_last_punct_tl
        \@@_ulem_ccglue:
        \@@_ulem_skip_punct_end:
        \UL@start
        \@@_ulem_class_group_begin:
      }
      { \@@_ulem_FullRight_and_CJK: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_punct_hskip:n}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_punct_hskip:n
  {
    \xeCJK_if_ulem_patch:TF
      { \xeCJK_ulem_hskip:n }
      { \@@_ulem_punct_hskip:n }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_punct_kern:n}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_punct_kern:n #1
  {
    \xeCJK_if_ulem_patch:TF
      {
        \dim_compare:nNnF {#1} = \c_zero_dim
          { \xeCJK_ulem_hskip:n {#1} }
      }
      { \@@_ulem_punct_kern:n {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_punct_breakable_kern:n}
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_punct_breakable_kern:n #1
  {
    \xeCJK_if_ulem_patch:TF
      {
        \xeCJK_class_group_end:
        \UL@stop \xeCJK_ulem_hskip:n {#1} \UL@start
        \@@_ulem_class_group_begin:
      }
      { \@@_ulem_punct_breakable_kern:n {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_ulem_glue:n,\@@_ulem_ccglue:}
% 在下划线状态下的分别代替 \tn{CJKglue} 等。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ulem_glue:n #1
  {
    \xeCJK_if_ulem_patch:TF
      {
        \tl_if_empty:NTF \l_@@_group_tag_tl
          { \UL@stop \@@_ulem_hskip:n {#1} \UL@start }
          {
            \str_if_eq_x:nnTF { \l_@@_group_tag_tl } { \c_@@_group_tag_tl }
              { \UL@stop \@@_ulem_hskip:n {#1} \UL@start }
              { \skip_horizontal:n {#1} }
          }
      }
      { \skip_horizontal:n {#1} }
  }
\cs_new_protected_nopar:Npn \xeCJK_make_group_tag:
  { \tl_set:Nx \l_@@_group_tag_tl { \c_@@_group_tag_tl } }
\tl_new:N \l_@@_group_tag_tl
\tl_const:Nn \c_@@_group_tag_tl
  {
    T \int_use:N \etex_currentgrouptype:D
    L \int_use:N \etex_currentgrouplevel:D
  }
\cs_new_protected_nopar:Npn \@@_ulem_ccglue:
  { { \skip_set_eq:NN \UL@skip \l_@@_ccglue_skip \UL@leaders } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xeCJKfntefon}
% \changes{v3.2.15}{2014/11/07}{完善选项。}
% 扩展 \tn{ULon} 的参数。
%    \begin{macrocode}
\NewDocumentCommand \xeCJKfntefon { s t- s o }
  {
    \xeCJK_ulem_boot:NNNn #1#2#3 {#4}
    \ULon
  }
\cs_new_eq:NN \xeCJK_ulem_on:n \UL@on
\cs_set_protected:Npn \UL@on #1
  { \xeCJK_ulem_on:n { \xeCJK_ulem_left: #1 \xeCJK_ulem_right: } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CJKunderline}
%    \begin{macrocode}
\DeclareDocumentCommand \CJKunderline { s t- s o }
  {
    \c_group_begin_token
      \xeCJK_fntef_boot:nnNNNn { underline } { uline } #1#2#3 {#4}
      \xeCJK_fntef_initial:nnn
        { \l_@@_uline_depth_tl }
        { \l_@@_uline_sep_tl }
        {
          \l_@@_uline_format_tl
          \tex_vrule:D
            height \dim_eval:n { \l_@@_uline_thickness_tl }
            depth \c_zero_dim
            width .2em
        }
      \ULon
  }
\DeclareDocumentCommand \varCJKunderline { }
  { \CJKunderline - }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CJKunderwave}
%    \begin{macrocode}
\DeclareDocumentCommand \CJKunderwave { s t- s o }
  {
    \c_group_begin_token
      \xeCJK_fntef_boot:nnNNNn { underwave } { uwave } #1#2#3 {#4}
      \xeCJK_fntef_initial:nnn
        { \l_@@_uwave_depth_tl }
        { \l_@@_uwave_sep_tl }
        { \l_@@_uwave_format_tl \l_@@_uwave_symbol_tl }
      \ULon
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CJKunderdblline}
%    \begin{macrocode}
\DeclareDocumentCommand \CJKunderdblline { s t- s o }
  {
    \c_group_begin_token
      \xeCJK_fntef_boot:nnNNNn { underdblline } { udbline } #1#2#3 {#4}
      \xeCJK_fntef_initial:nnn
        { \l_@@_udbline_depth_tl }
        { \l_@@_udbline_sep_tl }
        {
          \l_@@_udbline_format_tl
          \vbox_top:n
            {
              \tex_hrule:D
                height \dim_eval:n { \l_@@_udbline_thickness_tl }
                depth \c_zero_dim
                width .2em
              \tex_kern:D \dim_eval:n { \l_@@_udbline_gap_tl }
              \tex_hrule:D
                height \dim_eval:n { \l_@@_udbline_thickness_tl }
                depth \c_zero_dim
                width .2em
            }
        }
      \ULon
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CJKsout}
%    \begin{macrocode}
\DeclareDocumentCommand \CJKsout { s t- s o }
  {
    \c_group_begin_token
      \xeCJK_fntef_boot:nnNNNn { sout } { sout } #1#2#3 {#4}
      \xeCJK_fntef_initial:nn
        {
          \l_@@_sout_format_tl
          \tex_vrule:D
            height \dim_eval:n { \l_@@_sout_thickness_tl }
            depth \c_zero_dim
            width .2em
        }
        {
          \box_move_up:nn
            { \l_@@_sout_height_tl - \box_ht:N \l_@@_fntef_box / 2 }
            { \box_use:N \l_@@_fntef_box }
        }
      \ULon
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CJKxout}
%    \begin{macrocode}
\DeclareDocumentCommand \CJKxout { s t- s o }
  {
    \c_group_begin_token
      \xeCJK_fntef_boot:nnNNNn { xout } { xout } #1#2#3 {#4}
      \xeCJK_fntef_initial:nn
        {
          \l_@@_xout_format_tl
          \tex_kern:D -.1 em $/$
          \tex_kern:D -.1 em
        }
        {
          \box_move_up:nn
            { \box_dp:N \l_@@_fntef_box / 2 }
            { \box_use:N \l_@@_fntef_box }
        }
      \ULon
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CJKunderanyline}
% \changes{v3.2.15}{2014/11/07}{完善选项。}
%    \begin{macrocode}
\DeclareDocumentCommand \CJKunderanyline { s t- s o m m }
  {
    \c_group_begin_token
      \xeCJK_ulem_boot:NNNn #1#2#3 {#4}
      \xeCJK_fntef_initial:nn
        {#6}
        {
          \box_move_down:nn
            {#5}
            { \box_use:N \l_@@_fntef_box }
        }
      \tl_if_empty:NF \l_@@_ulem_boxdepth_tl
        { \box_set_dp:Nn \ULC@box { \l_@@_ulem_boxdepth_tl } }
      \tl_if_empty:NF \l_@@_ulem_sep_tl
        {
          \bool_set_true:N \l_@@_fntef_bool
          \dim_set:Nn \l_@@_fntef_dim
            { \l_@@_ulem_sep_tl + \box_dp:N \ULC@box }
        }
      \ULon
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_fntef_boot:nnNNNn}
% 处理参数问题。
%    \begin{macrocode}
\cs_new_protected:Npn \xeCJK_fntef_boot:nnNNNn #1#2#3#4#5#6
  {
    \bool_if:nT { #3 || #5 }
      { \bool_set_false:c { l_@@_#2_skip_bool } }
    \IfBooleanT #4
      { \bool_set_true:c { l_@@_#2_subtract_bool } }
    \IfNoValueF {#6}
      { \keys_set:nn { xeCJK / options / #1 } {#6} }
    \bool_set_eq:Nc \l_@@_ulem_skip_bool { l_@@_#2_skip_bool }
    \bool_set_eq:Nc \l_@@_ulem_hidden_bool { l_@@_#2_hidden_bool }
    \bool_set_eq:Nc \l_@@_ulem_subtract_bool { l_@@_#2_subtract_bool }
  }
\cs_new_protected:Npn \xeCJK_ulem_boot:NNNn #1#2#3#4
  {
    \bool_if:nT { #1 || #3 }
      { \bool_set_false:N \l_@@_ulem_skip_bool }
    \IfBooleanT #2
      { \bool_set_true:N \l_@@_ulem_subtract_bool }
    \IfNoValueF {#4}
      { \keys_set:nn { xeCJK / options / ulem } {#4} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_fntef_initial:n}
% 不支持下划线的嵌套使用。下划线嵌套使用时，里层的下划线会被放在盒子里，不能折行。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_fntef_initial:n
  {
    \xeCJK_leave_vmode:
    \bool_if:NTF \l_@@_nest_bool
      { \@@_warning:n { fntef-nesting } }
      {
        \bool_set_true:N \l_@@_nest_bool
        \@@_restore_shipout_fntef:
      }
    \xeCJK_fntef_sbox:n
  }
\cs_new_protected:Npn \xeCJK_fntef_initial:nn #1
  {
    \xeCJK_fntef_initial:n {#1}
    \bool_if:NF \l_@@_fntef_bool
      { \dim_zero:N \l_@@_fntef_dim }
    \markoverwith
  }
\cs_new_protected:Npn \xeCJK_fntef_initial:nnn #1#2#3
  {
    \xeCJK_fntef_initial:n {#3}
    \bool_if:NF \l_@@_fntef_bool
      {
        \bool_set_true:N \l_@@_fntef_bool
        \dim_set:Nn \l_@@_fntef_dim {#1}
      }
    \markoverwith
      {
        \box_move_down:nn
          { \l_@@_fntef_dim + \box_ht:N \l_@@_fntef_box }
          { \box_use:N \l_@@_fntef_box }
      }
    \dim_set:Nn \l_@@_fntef_dim { #2 + \box_dp:N \ULC@box }
  }
\box_new:N \l_@@_fntef_box
\cs_new_eq:NN \xeCJKfntefbox \l_@@_fntef_box
\bool_new:N \l_@@_nest_bool
\bool_new:N \l_@@_fntef_bool
\@@_msg_new:nn { fntef-nesting }
  { Nesting~is~not~supported. }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[var,internal]{\l_@@_fntef_dim}
% 记录下划线或者下划符号的深度，以便它们嵌套使用时能自动调整好距离。
% \tn{ULdepth} 被 \pkg{ulem} 初始化为 \tn{maxdimen}。下划线嵌套时，\pkg{ulem}
% 要使用它作计算，可能会溢出。为简便起见，\cs{l_@@_fntef_dim} 与 \tn{ULdepth}
% 共用一个寄存器。
%    \begin{macrocode}
\cs_new_eq:NN \l_@@_fntef_dim \ULdepth
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_fntef_sbox:n}
% 与 \cs{hcoffin_set:Nn} 和 \LaTeXe{} 的 \tn{sbox} 功能类似，确保颜色的正确。
% 虽然 \texttt{coffin} 可以更方便的操作盒子，但速度要慢一点。并且，我们的需求
% 也比较简单，就不用它了。
%    \begin{macrocode}
\cs_new_protected:Npn \xeCJK_fntef_sbox:n #1
  {
    \hbox_set:Nn \l_@@_fntef_box
      {
        \color_group_begin:
          \color_ensure_current:
          #1
        \color_group_end:
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_leave_vmode:}
% 功能与 \tn{leavevmode} 类似，但不会影响 \tn{everypar}。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_leave_vmode:
  {
    \if_mode_vertical:
      \exp_after:wN \tex_indent:D
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% 最合适的是用 \pkg{xtemplate} 宏包来实现，但是比较难于用 \tn{xeCJKsetup} 来统一
% 设置，所以这里还是用土办法。
%    \begin{macrocode}
\keys_define:nn { xeCJK / options }
  {
    underdot / symbol          .tl_set:N = \l_@@_udot_symbol_tl ,
    underdot / depth           .tl_set:N = \l_@@_udot_depth_tl ,
    underdot / sep             .tl_set:N = \l_@@_udot_sep_tl ,
    underdot / format          .tl_set:N = \l_@@_udot_format_tl ,
    underdot / boxdepth        .tl_set:N = \l_@@_udot_boxdepth_tl ,
    symbol / sep               .tl_set:N = \l_@@_symbol_sep_tl ,
    symbol / boxdepth          .tl_set:N = \l_@@_symbol_boxdepth_tl ,
    underline / skip         .bool_set:N = \l_@@_uline_skip_bool ,
    underline / hidden       .bool_set:N = \l_@@_uline_hidden_bool ,
    underline / subtract     .bool_set:N = \l_@@_uline_subtract_bool ,
    underline / thickness      .tl_set:N = \l_@@_uline_thickness_tl ,
    underline / depth          .tl_set:N = \l_@@_uline_depth_tl ,
    underline / sep            .tl_set:N = \l_@@_uline_sep_tl ,
    underline / format         .tl_set:N = \l_@@_uline_format_tl ,
    underdblline / skip      .bool_set:N = \l_@@_udbline_skip_bool ,
    underdblline / hidden    .bool_set:N = \l_@@_udbline_hidden_bool ,
    underdblline / subtract  .bool_set:N = \l_@@_udbline_subtract_bool ,
    underdblline / thickness   .tl_set:N = \l_@@_udbline_thickness_tl ,
    underdblline / depth       .tl_set:N = \l_@@_udbline_depth_tl ,
    underdblline / sep         .tl_set:N = \l_@@_udbline_sep_tl ,
    underdblline / format      .tl_set:N = \l_@@_udbline_format_tl ,
    underdblline / gap         .tl_set:N = \l_@@_udbline_gap_tl ,
    underwave / skip         .bool_set:N = \l_@@_uwave_skip_bool ,
    underwave / hidden       .bool_set:N = \l_@@_uwave_hidden_bool ,
    underwave / subtract     .bool_set:N = \l_@@_uwave_subtract_bool ,
    underwave / symbol         .tl_set:N = \l_@@_uwave_symbol_tl ,
    underwave / depth          .tl_set:N = \l_@@_uwave_depth_tl ,
    underwave / sep            .tl_set:N = \l_@@_uwave_sep_tl ,
    underwave / format         .tl_set:N = \l_@@_uwave_format_tl ,
    sout / skip              .bool_set:N = \l_@@_sout_skip_bool ,
    sout / hidden            .bool_set:N = \l_@@_sout_hidden_bool ,
    sout / subtract          .bool_set:N = \l_@@_sout_subtract_bool ,
    sout / thickness           .tl_set:N = \l_@@_sout_thickness_tl ,
    sout / height              .tl_set:N = \l_@@_sout_height_tl ,
    sout / format              .tl_set:N = \l_@@_sout_format_tl ,
    xout / skip              .bool_set:N = \l_@@_xout_skip_bool ,
    xout / hidden            .bool_set:N = \l_@@_xout_hidden_bool ,
    xout / subtract          .bool_set:N = \l_@@_xout_subtract_bool ,
    xout / format              .tl_set:N = \l_@@_xout_format_tl ,
    ulem / skip              .bool_set:N = \l_@@_ulem_skip_bool ,
    ulem / hidden            .bool_set:N = \l_@@_ulem_hidden_bool ,
    ulem / subtract          .bool_set:N = \l_@@_ulem_subtract_bool ,
    ulem / sep                 .tl_set:N = \l_@@_ulem_sep_tl ,
    ulem / boxdepth            .tl_set:N = \l_@@_ulem_boxdepth_tl
  }
\clist_map_inline:nn
  { underdot , underline , underdblline , underwave , sout , xout }
  {
    \keys_define:nn { xeCJK / options }
      { #1 .meta:nn = { xeCJK / options / #1 } { ##1 } }
  }
\keys_set:nn { xeCJK / options }
  {
    underdot / symbol        = \normalfont . ,
    underdot / depth         = 0.20 em ,
    underdot / sep           = 0.04 em ,
    symbol / sep             = \c_zero_dim ,
    underline / skip         = true ,
    underline / thickness    = \ULthickness ,
    underline / depth        = 0.20 em ,
    underline / sep          = 0.07 em ,
    underdblline / skip      = true ,
    underdblline / thickness = \ULthickness ,
    underdblline / depth     = 0.20 em ,
    underdblline / sep       = 0.17 em ,
    underdblline / gap       = 1.1 pt ,
    underwave / skip         = true ,
    underwave / symbol       = \sixly \tex_char:D 58 \exp_stop_f: ,
    underwave / depth        = 0.20 em ,
    underwave / sep          = 0.00 em ,
    sout / skip              = true ,
    sout / thickness         = \ULthickness ,
    sout / height            = 0.35 em ,
    xout / skip              = true
  }
\cs_if_free:NF \color
  {
    \keys_set:nn { xeCJK / options }
      {
        underdot / format     = \color { red } ,
        underline / format    = \color { blue } ,
        underdblline / format = \color { blue } ,
        underwave / format    = \color { blue } ,
        sout / format         = \color { red } ,
        xout / format         = \color { blue }
      }
  }
%    \end{macrocode}
%
% \begin{macro}{\CJKunderanysymbol}
%    \begin{macrocode}
\DeclareDocumentCommand \CJKunderanysymbol { o m m m }
  {
    \xeCJK_under_symbol:nnnnnn { symbol } { symbol } {#1} {#2} {#3} {#4}
    \tex_ignorespaces:D
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\CJKunderdot}
% \tn{CJKunderdot} 是 \tn{CJKunderanysymbol} 的特殊情况。\pkg{CJKfntef} 原来使用
% 的是数学符号 \tn{cdot}，这里改成更合适的 |.|。
%    \begin{macrocode}
\DeclareDocumentCommand \CJKunderdot { o m }
  {
    \xeCJK_under_symbol:nnnnnn { underdot } { udot }
      {#1}
      { \l_@@_udot_depth_tl }
      { \l_@@_udot_format_tl \l_@@_udot_symbol_tl }
      {#2}
    \tex_ignorespaces:D
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_under_symbol:nnnnnn}
% 当处在下划线中时，我们先断开下划线，在分组外设置下划符号。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_under_symbol:nnnnnn
  {
    \xeCJK_if_ulem_patch:TF
      { \@@_under_symbol_auxi:nnnnnn }
      { \@@_under_symbol_auxii:nnnnnn }
  }
\cs_new_protected:Npn \@@_under_symbol_auxi:nnnnnn #1#2#3#4#5#6
  {
    \xeCJK_ulem_right: \UL@stop
    \group_begin:
      \xeCJK_under_symbol_initial:nnnnn {#1} {#2} {#3} {#4} {#5}
      \UL@start \xeCJK_ulem_right_node:
        #6
      \xeCJK_ulem_right: \UL@stop
    \group_end:
    \UL@start \xeCJK_ulem_right_node:
  }
\cs_new_protected:Npn \@@_under_symbol_auxii:nnnnnn #1#2#3#4#5#6
  {
    \xeCJK_leave_vmode:
    \group_begin:
      \xeCJK_under_symbol_initial:nnnnn {#1} {#2} {#3} {#4} {#5}
      #6
    \group_end:
  }
\cs_new_protected:Npn \xeCJK_under_symbol_initial:nnnnn #1#2#3#4#5
  {
    \IfNoValueF {#3}
      { \keys_set:nn { xeCJK / options / #1 } {#3} }
    \xeCJK_fntef_sbox:n {#5}
    \bool_if:NTF \l_@@_fntef_bool
      { \xeCJK_make_under_symbol:n { \l_@@_fntef_dim } }
      {
        \bool_set_true:N \l_@@_fntef_bool
        \xeCJK_make_under_symbol:n {#4}
      }
    \tl_if_empty:cF { l_@@_#2_boxdepth_tl }
      {
        \box_set_dp:Nn \l_@@_under_symbol_box
          { \use:c { l_@@_#2_boxdepth_tl } }
      }
    \dim_set:Nn \l_@@_fntef_dim
      { \use:c { l_@@_#2_sep_tl } + \box_dp:N \l_@@_under_symbol_box }
    \xeCJK_swap_cs:NN \CJKsymbol \@@_under_CJKsymbol:N
    \@@_restore_shipout_CJKsymbol:
  }
\box_new:N \l_@@_under_symbol_box
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_make_under_symbol:n}
% 我们量取“一”的宽度作为汉字的宽度。
%    \begin{macrocode}
\cs_new_protected:Npn \xeCJK_make_under_symbol:n #1
  {
    \hbox_set:Nn \l_@@_under_symbol_box
      {
        \box_move_down:nn { #1 + \box_ht:N \l_@@_fntef_box }
          {
            \hbox_to_zero:n
              {
                \xeCJK_select_font:
                \tex_kern:D \etex_fontcharwd:D \tex_font:D "4E00 \exp_stop_f:
                \tex_hss:D \box_use:N \l_@@_fntef_box \tex_hss:D
              }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_restore_shipout_CJKsymbol:}
% \changes{v3.2.3}{2013/06/04}{解决 \tn{CJKunderdot} 跨页使用时影响到页眉页脚的问题。}
% \tn{CJKunderdot} 中对 \tn{CJKsymbol} 的修改会影响到页眉和页脚，需要小心处理。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_restore_shipout_CJKsymbol:
  {
    \tl_put_right:Nn \l_@@_fntef_shipout_tl
      { \xeCJK_swap_cs:NN \CJKsymbol \@@_under_CJKsymbol:N }
    \@@_restore_shipout_fntef:
    \xeCJK_cs_clear:N \@@_restore_shipout_CJKsymbol:
  }
\cs_new_protected:Npn \@@_restore_shipout_fntef:
  {
    \tl_put_right:Nn \l_@@_fntef_shipout_tl
      {
        \bool_set_false:N \l_@@_fntef_bool
        \dim_zero:N \l_@@_fntef_dim
      }
    \xeCJK_cs_clear:N \@@_restore_shipout_fntef:
  }
\tl_new:N \l_@@_fntef_shipout_tl
\xeCJK_add_to_shipout:n { \l_@@_fntef_shipout_tl }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_under_CJKsymbol:N}
% 盒子放在汉字的左侧，比较容易处理状态转移的问题。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_under_CJKsymbol:N
  {
    \box_use:N \l_@@_under_symbol_box
    \xeCJK_no_break: \@@_under_CJKsymbol:N
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}[internal]{CJKfilltwosides}
% \changes{v3.2.4}{2012/06/26}{改用 \texttt{minipage} 和 \LaTeX 表格（\texttt{tabular}）来实现。}
% 使用 \texttt{minipage} 和 \LaTeX 表格（\texttt{tabular}）来定义 |CJKfilltwosides| 环境。
% 可选参数 |#1| 表示环境的垂直对齐位置，默认居中；参数 |#2| 表示环境的宽度。
% 带星号的环境，如果 |#2| 不大于零或者不大于环境最长文本行的宽度，则取环境的自然宽度。
%    \begin{macrocode}
\DeclareDocumentEnvironment { CJKfilltwosides } { O { c } m }
  {
    \use:x { \exp_not:N \minipage [#1] { \dim_eval:n {#2} } }
    \cs_set_eq:NN \CJKglue \xeCJK_fntef_hfilll:
  }
  {
    \endminipage
    \ignorespacesafterend
  }
\NewEnviron { CJKfilltwosides* } [ 2 ] [ c ]
  {
    \cs_set_eq:NN \CJKglue \xeCJK_fntef_hfilll:
    \tl_set:Nn \arraystretch { 1 }
    \cs_if_free:NF \extrarowheight
      { \cs_set_eq:NN \extrarowheight \c_zero_dim }
    \use:x { \@@_fill_two_sides:nn {#1} { \dim_eval:n {#2} } }
  }
  [ \ignorespacesafterend ]
\cs_new_protected:Npn \@@_fill_two_sides:nn #1#2
  {
    \dim_compare:nNnTF {#2} > \c_zero_dim
      {
        \hbox_set:Nn \l_@@_tmp_box
          {
            \tabular [#1] { @ { } c @ { } }
              \BODY
            \endtabular
          }
        \dim_compare:nNnTF {#2} > { \box_wd:N \l_@@_tmp_box }
          {
            \tabular [#1] { @ { } p {#2} @ { } }
              \BODY
            \endtabular
          }
          { \box_use:N \l_@@_tmp_box }
      }
      {
        \tabular [#1] { @ { } c @ { } }
          \BODY
        \endtabular
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\xeCJK_fntef_hfilll:}
% \pkg{colortbl} 将表格 |c| 列用于填充的 \tn{hfil} 改为了更高阶的 \texttt{fill}，
% 影响到了 \env{CJKfilltwosides*}。因此，我们也要用高阶的 \texttt{filll}。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \xeCJK_fntef_hfilll:
  { \skip_horizontal:N \c_@@_filll_skip }
\skip_new:N \c_@@_filll_skip
\skip_set:Nn  \c_@@_filll_skip { \c_zero_dim plus 1 filll }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</fntef>
%    \end{macrocode}
%
% \subsection{\pkg{xeCJK-listings}}
%
% \changes{v3.2.2}{2012/06/04}{增加小宏包 \pkg{xeCJK-listings}，用于支持 \pkg{listings} 宏包。}
% \changes{v3.2.3}{2012/06/06}{完善对 \pkg{listings} 宏包的支持。}
%
% 仿照 \package{luatexja} 宏包中 \pkg{lltjp-listings} 的处理，支持 \package{listings} 宏包。
%
%    \begin{macrocode}
%<*listings>
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareOption* { \PassOptionsToPackage { \CurrentOption } { xeCJK } }
\ProcessOptions \scan_stop:
%    \end{macrocode}
%
%    \begin{macrocode}
\RequirePackage { xeCJK }
\RequirePackage { listings }
%    \end{macrocode}
%
%    \begin{macrocode}
\lst@AddToHook { Init } { \@@_listings_initial_hook: }
\lst@AddToHook { SelectCharTable } { \@@_listings_toks_hook: }
\lst@AddToHook { OutputBox }
  {
    \tl_set_eq:NN \l_xeCJK_punct_style_tl \c_@@_punct_style_plain_tl
    \l_@@_restore_listings_toks_tl
    \@@_listings_output_IVS:
  }
\lst@AddToHook { PreSet } { \bool_set_true:N \l_@@_listings_env_bool }
%    \end{macrocode}
%
% \begin{macro}[internal]{\@@_listings_initial_hook:}
% \changes{v3.2.3}{2013/06/04}
% {解决 \texttt{listings} 坏境中代码行号输出不正确的问题，并解决在其中跨页时对页眉
%  和页脚的影响。}
% \changes{v3.2.15}{2014/11/10}{修正 \texttt{breaklines} 无效的问题。}
% 为使代码行号结果正确，需要在 \tn{lst@numberstyle} 中恢复 \tn{XeTeXinterchartoks}。
% 在 \texttt{listings} 环境中换页时，对 \tn{XeTeXinterchartoks} 的修改会影响到
% 页眉和页脚，需要在 \tn{shipout} 盒子中恢复成正常定义。加入 \cs{tex_noindent:D}
% 是为了进入水平模式，防止汉字出现在首行的时候可能会产生额外空行。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_listings_initial_hook:
  {
    \tex_noindent:D
    \bool_gset_false:N \g_@@_listings_IVS_bool
    \tl_put_left:Nn \lst@numberstyle { \l_@@_restore_listings_toks_tl }
    \xeCJK_add_to_shipout:n { \l_@@_restore_listings_toks_tl }
    \lst@ifbreaklines
      \cs_set_eq:NN \@@_listings_CJK_toks_hook: \@@_listings_breaklines_toks:
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_listings_toks_hook:}
% 采用不同的 \tn{XeTeXinterchartoks} 处理方式，输入的时候是将汉字加入到 \pkg{listings}
% 的输出队列，实际输出的时候是普通文字。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_listings_toks_hook:
  {
    \tl_set:Nx \l_@@_restore_listings_toks_tl
      {
        \@@_backup_inter_class_toks:nn { Boundary } { Default }
        \@@_backup_inter_class_toks:nn { Boundary } { CJK }
        \@@_backup_inter_class_toks:nn { Boundary } { IVS }
        \@@_backup_inter_class_toks:nn { Boundary } { HangulJamo }
        \@@_backup_inter_class_toks:nn { Boundary } { FullLeft }
        \@@_backup_inter_class_toks:nn { Boundary } { FullRight }
      }
    \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
      {
        \tl_put_right:Nx \l_@@_restore_listings_toks_tl
          { \@@_backup_inter_class_toks:nn { Boundary } { CJK/##1 } }
      }
    \xeCJK_inter_class_toks:nnn { Boundary } { Default }
      { \@@_listings_process_Default:N }
    \xeCJK_inter_class_toks:nnn { Boundary } { IVS }
      { \@@_listings_process_IVS:nN { \c_zero } }
    \@@_listings_CJK_toks_hook:
  }
\tl_new:N \l_@@_restore_listings_toks_tl
\cs_new_nopar:Npn \@@_backup_inter_class_toks:nn #1#2
  {
    \xeCJK_inter_class_toks:nnn {#1} {#2}
      { \xeCJK_get_inter_class_toks:nn {#1} {#2} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_listings_CJK_toks_hook:,\@@_listings_breaklines_toks:}
% 根据 \texttt{breaklines} 选项的使用与否，选择不同的处理方式。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_listings_CJK_toks_hook:
  {
    \xeCJK_inter_class_toks:nnn { Boundary } { CJK }
      { \@@_listings_process_CJK:nN { \c_two } }
    \xeCJK_inter_class_toks:nnn { Boundary } { FullLeft }
      { \@@_listings_process_CJK:nN { \c_two } }
    \xeCJK_inter_class_toks:nnn { Boundary } { FullRight }
      { \@@_listings_process_CJK:nN { \c_two } }
    \xeCJK_inter_class_toks:nnn { Boundary } { HangulJamo }
      { \@@_listings_process_CJK:nN { \c_two } }
    \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
      {
        \xeCJK_inter_class_toks:nnn { Boundary } { CJK/##1 }
          { \@@_listings_process_CJK:nN { \c_two } }
      }
  }
\cs_new_protected_nopar:Npn \@@_listings_breaklines_toks:
  {
    \xeCJK_inter_class_toks:nnn { Boundary } { CJK }
      { \@@_listings_process_breaklines_CJK:nN { \c_two } }
    \xeCJK_inter_class_toks:nnn { Boundary } { HangulJamo }
      { \@@_listings_process_breaklines_CJK:nN { \c_two } }
    \xeCJK_inter_class_toks:nnn { Boundary } { FullLeft }
      { \@@_listings_process_FullLeft:nN { \c_two } }
    \xeCJK_inter_class_toks:nnn { Boundary } { FullRight }
      { \@@_listings_process_FullRight:nN { \c_two } }
    \seq_map_inline:Nn \g_@@_CJK_sub_class_seq
      {
        \xeCJK_inter_class_toks:nnn { Boundary } { CJK/##1 }
          { \@@_listings_process_breaklines_CJK:nN { \c_two } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_listings_process_Default:N,\@@_listings_process_CJK:nN}
% \changes{v3.2.3}{2013/06/08}{在 \texttt{listings} 坏境中对 \tn{charcode} 大于
% $255$ 的字符根据其 \tn{catcode} 区分 \texttt{letter} 和 \texttt{other}。}
% 对于 \tn{charcode} 大于 $255$ 的字符，根据 \tn{catcode} 进行处理。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_listings_process_Default:N #1
  {
    \token_if_letter:NTF #1
      { \lst@ProcessLetter #1 }
      { \lst@ProcessOther  #1 }
  }
\cs_new_protected_nopar:Npn \@@_listings_process_CJK:nN #1#2
  {
    \token_if_letter:NTF #2
      { \@@_listings_process_letter:nN {#1} #2 }
      { \@@_listings_process_other:nN  {#1} #2 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_listings_append:nN}
% 普通 CJK 字符的宽度为一般基本宽度的两倍，IVS 类不增加宽度。这里有一个问题，
% 对 CJK 字符类中的一些半角字符（例如半角日文假名）没有区分开。\pkg{listings} 通过
% 重定义 \tn{lst@Append} 将代码写入外部文件，因此需要保留。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_listings_append:nN #1#2
  {
    \int_add:Nn \lst@length { #1 - \c_one }
    \lst@Append #2
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_listings_process_letter:nN,\@@_listings_process_other:nN}
% 在 \texttt{letter} 类中区分汉字和西文字母。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_listings_process_letter:nN
  {
    \lst@whitespacefalse
    \bool_if:NTF \l_@@_listings_letter_bool
      { \lst@lettertrue }
      {
        \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi:
        \bool_set_true:N \l_@@_listings_letter_bool
      }
    \@@_listings_append:nN
  }
\cs_new_protected_nopar:Npn \@@_listings_process_other:nN #1#2
  {
    \lst@whitespacefalse
    \bool_if:NTF \l_@@_listings_letter_bool
      {
        \lst@Output \lst@letterfalse
        \bool_set_false:N \l_@@_listings_letter_bool
      }
      { \lst@ifletter \lst@Output \lst@letterfalse \fi: }
    \cs_set_eq:NN \lst@lastother #2
    \@@_listings_append:nN {#1} #2
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.4}{2012/07/05}
% {使 \pkg{listings} 的 \texttt{breaklines} 选项对 CJK 字符类可用，并保持标点符号的禁则。}
%
% \begin{macro}[internal]
% {\@@_listings_process_breaklines_CJK:nN,
%  \@@_listings_process_FullLeft:nN,
%  \@@_listings_process_FullRight:nN}
% 当使用 \texttt{breaklines} 选项时，立即输出之前的单个文字，以便于断行。并将标点
% 与它前/后的 CJK 文字放在同一个盒子中，以保持禁则。但是不能区分 letter 和 other。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_listings_process_breaklines_CJK:nN
  {
    \lst@whitespacefalse
    \bool_if:NTF \l_@@_listings_letter_bool
      {
        \int_compare:nNnF \l_@@_listings_flag_int = \c_two { \lst@Output }
        \lst@lettertrue
      }
      {
        \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi:
        \bool_set_true:N \l_@@_listings_letter_bool
      }
    \int_set_eq:NN \l_@@_listings_flag_int \c_one
    \@@_listings_append:nN
  }
\cs_new_protected_nopar:Npn \@@_listings_process_FullLeft:nN #1#2
  {
    \lst@whitespacefalse
    \bool_if:NTF \l_@@_listings_letter_bool
      {
        \bool_if:nF
          {
            \int_compare_p:nNn \l_@@_listings_flag_int = \c_two ||
            ( \int_compare_p:nNn \l_@@_listings_flag_int = \c_three &&
              ! \l_@@_punct_breakable_bool )
          }
          { \lst@Output }
        \lst@lettertrue
      }
      {
        \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi:
        \bool_set_true:N \l_@@_listings_letter_bool
      }
    \int_set_eq:NN \l_@@_listings_flag_int \c_two
    \@@_listings_append:nN {#1} #2
  }
\cs_new_protected_nopar:Npn \@@_listings_process_FullRight:nN #1#2
  {
    \lst@whitespacefalse
    \bool_if:NTF \l_@@_listings_letter_bool
      {
        \bool_if:nT
          {
            \int_compare_p:nNn \l_@@_listings_flag_int < \c_two &&
            \@@_punct_if_long_p:N #2
          }
          { \lst@Output }
        \lst@lettertrue
      }
      {
        \lst@ifletter \lst@Output \else: \lst@OutputOther \lst@lettertrue \fi:
        \bool_set_true:N \l_@@_listings_letter_bool
      }
    \int_set_eq:NN \l_@@_listings_flag_int \c_three
    \@@_listings_append:nN {#1} #2
  }
\int_new:N \l_@@_listings_flag_int
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\lst@AppendLetter,\lst@AppendOther}
%    \begin{macrocode}
\cs_set_protected_nopar:Npn \lst@AppendLetter
  {
    \bool_if:NTF \l_@@_listings_letter_bool
      {
        \lst@Output \lst@lettertrue
        \bool_set_false:N \l_@@_listings_letter_bool
      }
      { \reverse_if:N \lst@ifletter \lst@OutputOther \lst@lettertrue \fi: }
    \lst@ifbreaklines \int_zero:N \l_@@_listings_flag_int \fi:
    \lst@Append
  }
\cs_set_protected_nopar:Npn \lst@AppendOther
  {
    \bool_if:NTF \l_@@_listings_letter_bool
      {
        \lst@Output \lst@letterfalse
        \bool_set_false:N \l_@@_listings_letter_bool
      }
      { \lst@ifletter \lst@Output \lst@letterfalse \fi: }
    \lst@ifbreaklines \int_zero:N \l_@@_listings_flag_int \fi:
    \tex_futurelet:D \lst@lastother \lst@Append
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_listings_process_IVS:nN}
% \texttt{IVS} 类作为 \texttt{letter} 处理，不用增加 \tn{lst@length}。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_listings_process_IVS:nN
  {
    \reverse_if:N \lst@ifflexible
      \bool_gset_true:N \g_@@_listings_IVS_bool
    \fi:
    \@@_listings_process_letter:nN
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_listings_output_IVS:}
% 在使用 \texttt{columns=fixed} 选项时，\pkg{listings} 会在输出盒子里的每个字符
% 之间加入 \tn{hss}，这就破坏了 \XeTeX 将基本字和 IVS 正确的组合起来。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_listings_output_IVS:
  {
    \reverse_if:N \lst@ifflexible
      \bool_if:NT \g_@@_listings_IVS_bool
        {
          \bool_gset_false:N \g_@@_listings_IVS_bool
          \xeCJK_cs_clear:N \lst@FillOutputBox
          \cs_set_eq:NN \CJKglue \tex_hss:D
        }
    \fi:
  }
\bool_new:N \g_@@_listings_IVS_bool
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_listings_peek_active_loop:TF}
% \tn{lstinline} 通过判断参数中第一个字符是否是 \texttt{active} 类来区分
% 它是否被用在其它宏的参数之中。如果这第一个字符不在 \pkg{listings} 预定义的
% 符号表中，判断就会出问题。我们在这里通过一个循环跳过这些字符。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_listings_peek_active_loop:TF #1#2#3
  {
    \token_if_active:NTF #3
      { #1#3 }
      {
        \token_if_cs:NTF #3
          { #2#3 }
          {
            \int_compare:nNnTF { `#3 } > { \lst@ifec 255 \else: 127 \fi: }
              { \@@_listings_peek_active_loop:TF { #1#3 } { #2#3 } }
              { #2#3 }
          }
      }
  }
\cs_set_eq:NN \lst@IfNextCharActive \@@_listings_peek_active_loop:TF
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_listings_inside_convert:nw,\@@_listings_inline_group:w}
% 当 \tn{lstinline} 被使用在参数中时，\pkg{listings} 会使用一个循环逐个将
% \tn{lstinline} 参数中的字符设置为活动字符。我们可以通过 \cs{tl_set_rescan:Nnn}
% 来完成这里的 \tn{catcode} 转换，避免将 \tn{charcode} 超过 $255$ 的字符都设置为
% 活动字符。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_listings_inside_convert:nw #1 ~ \@empty
  {
    \tl_set_rescan:Nnn \l_@@_tmp_tl { } {#1}
    \@@_set_listings_escape:
    \tl_put_right:NV \lst@arg \l_@@_tmp_tl
  }
\cs_set_eq:NN \lst@InsideConvert@ \@@_listings_inside_convert:nw
\cs_new_protected_nopar:Npn \@@_listings_inline_group:w
  {
    \exp_after:wN \@@_listings_inline_group:n
    \exp_after:wN { \if_false: } \fi:
  }
\cs_set_eq:NN \lst@InlineGJ \@@_listings_inline_group:w
\cs_new_protected:Npn \@@_listings_inline_group:n #1
  {
    \tl_set_rescan:Nnn \lst@arg { } {#1}
    \@@_set_listings_escape:
    \lst@InlineGJEnd
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_set_listings_escape:}
% 由于我们在上面的修改，需要保留 |\| 用于转义 \tn{lstinline} 参数中的某些 \TeX
% 特殊字符，与原来宏包一致。
%    \begin{macrocode}
\group_begin:
\cs_set:Npn \@@_tmp:w #1
  {
    \group_end:
    \cs_new_protected:Npn \@@_set_listings_escape:
      { \xeCJK_swap_cs:NN #1 \@@_listings_escape:N }
    \cs_new_protected:Npn \@@_listings_escape:N ##1
      { \cs_if_eq:NNTF #1 ##1 { \@@_listings_escape:N } {##1} }
  }
\use:n
  {
    \char_set_catcode_active:N \\
    \@@_tmp:w
  }
  { \ }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</listings>
%    \end{macrocode}
%
% \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno
%    \begin{macrocode}
%<@@=xunadd>
%    \end{macrocode}\egroup
%
% \subsection{\pkg{xunicode-addon}}
%
% \changes{v3.2.5}{2013/07/18}
% {增加小宏包 \pkg{xunicode-addon}，为 \pkg{xunicode} 提供判断字符是否存在的功能。}
% \changes{v3.2.9}{2013/12/08}
% {文档部分增加 \pkg{xunicode} 定义的符号表。}
%
%    \begin{macrocode}
%<*xunicode>
%    \end{macrocode}
%
% \pkg{xunicode} 对编码相关的符号命令的定义中用的是诸如 |\char"0022\relax| 的形式。
% 例如 \tn{textbar} 被展开为 |\char"007C\relax|。并且诸如下述的定义是无效的：
% \begin{verbatim}
%   \DeclareUTFcomposite[\UTFencname]{x1EBF}{\'}{\^e}
% \end{verbatim}
% 我们在这里做的修改是把符号命令定义为实际的字符并且使上述定义生效。另外在使用
% 这些符号命令的时候，先判断当前字体中是否存在对应的字符，如果不存在，则使用这
% 些符号命令的默认设置。
%
%    \begin{macrocode}
\pdftex_if_engine:T
  {
    \msg_new:nnnn { xunicode-addon } { cannot-use-pdftex }
      { This~package~requires~either~XeTeX~or~LuaTeX~to~function.}
      {
        You~must~change~your~typesetting~engine~to,~e.g.,\\
        "xelatex"~or~"lualatex"~instead~of~plain~"latex"~or~"pdflatex".
      }
    \msg_critical:nn { xunicode-addon } { cannot-use-pdftex }
  }
\RequirePackage { xparse }
%    \end{macrocode}
%
% 宏包选项是编码的名字。
%
%    \begin{macrocode}
\clist_new:N \g_@@_encname_clist
\DeclareOption*
  { \clist_gput_left:NV \g_@@_encname_clist \CurrentOption }
\ProcessOptions \scan_stop:
\tl_if_exist:NT \UTFencname
  { \clist_gput_left:Nx \g_@@_encname_clist { \UTFencname } }
%    \end{macrocode}
%
% 若 \pkg{xunicode} 已经被调用，则在宏包结束的时候，重新设置 \tn{UTFencname}
% 对应的编码命令。否则设置 \tn{UTFencname}，如果使用的是 \hologo{LuaLaTeX}，则
% 需要作一些设置，使得 \pkg{xunicode} 可用。
%
%    \begin{macrocode}
\@ifpackageloaded { xunicode } { }
  {
    \clist_get:NNF \g_@@_encname_clist \UTFencname
      {
        \xetex_if_engine:TF
          { \tl_set:Nn \UTFencname { EU1 } }
          { \tl_set:Nn \UTFencname { EU2 } }
        \clist_set_eq:NN \g_@@_encname_clist \UTFencname
      }
    \xetex_if_engine:TF
      { \RequirePackage { xunicode } }
      {
        \cs_set_eq:NN \@@_tmp:w \XeTeXpicfile
        \cs_set_eq:NN \XeTeXpicfile \prg_do_nothing:
        \RequirePackage { xunicode }
        \cs_set_eq:NN \XeTeXpicfile \@@_tmp:w
      }
  }
\AtEndOfPackage { \ReloadXunicode { \g_@@_encname_clist } }
%    \end{macrocode}
%
% \begin{macro}[internal]{\ReloadXunicode}
% 参数可以是多个编码，设置这些编码对应的命令。如果编码没有预先声明，则给出
% 一个错误警告。
%    \begin{macrocode}
\RenewDocumentCommand \ReloadXunicode { m }
  {
    \clist_set:Nx \l_@@_encname_clist {#1}
    \clist_remove_duplicates:N \l_@@_encname_clist
    \use:x
      {
        \bool_if:NT \l__kernel_expl_bool { \ExplSyntaxOff }
        \char_set_catcode_letter:n { 64 }
        \@@_reload:N \exp_not:N \l_@@_encname_clist
        \char_set_catcode:nn { 64 } { \char_value_catcode:n { 64 } }
        \bool_if:NT \l__kernel_expl_bool { \ExplSyntaxOn }
      }
  }
\cs_new_protected:Npn \@@_reload:N #1
  {
    \cs_set_eq:NN \@@_tmp:w \iftipaonetoken
    \cs_set_eq:NN \iftipaonetoken \scan_stop:
    \clist_map_inline:Nn #1
      {
        \cs_if_exist:cTF { T@ ##1 }
          {
            \tl_set:Nx \UTFencname {##1}
            \clist_gput_right:Nx \g_@@_encname_clist {##1}
            \file_input:n { xunicode.sty }
            \file_input:n { xunicode-extra.def }
          }
          { \msg_error:nnn { xunicode-addon } { encoding-unknown } {##1} }
      }
    \cs_set_eq:NN \iftipaonetoken \@@_tmp:w
    \clist_gremove_duplicates:N \g_@@_encname_clist
  }
\clist_new:N \l_@@_encname_clist
\msg_new:nnnn { xunicode-addon } { encoding-unknown }
  { Encoding~scheme~"#1"~unknown. }
  {
    You~may~use \\\\
    \token_to_str:N \usepackage [ #1 , \encodingdefault ] {fontenc} \\\\
    before~xunicode-addon~or~xunicode.
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFmathsymbols}
% \changes{v3.2.8}{2013/12/04}{修正 \tn{UseMathAsText} 的功能，恢复 \tn{hbar}
% 和增加以 \texttt{text} 打头的文本符号命令。}
% 将文本符号定义为 \tn{protected} 宏后，为了与 \pkg{hyperref} 的书签功能兼容
% 需要作一点额外处理。
%    \begin{macrocode}
\RenewDocumentCommand \DeclareUTFmathsymbols { m }
  {
    \bool_if:NT \l_@@_math_as_UTF_text_bool
      {
        \seq_map_inline:Nn \l_@@_math_as_UTF_text_seq
          { \@@_declare_math_as_UTF_text:n {##1} }
        \bool_set_false:N \l_@@_math_as_UTF_text_bool
      }
  }
\seq_new:N \l_@@_math_as_UTF_text_seq
\seq_set_from_clist:Nn \l_@@_math_as_UTF_text_seq
  { hbar , Finv , aleph , beth , gimel , daleth , Game }
\bool_new:N \l_@@_math_as_UTF_text_bool
\RenewDocumentCommand \UseMathAsText { }
  {
    \math@s@text@true
    \bool_set_true:N \l_@@_math_as_UTF_text_bool
  }
\@onlypreamble \UseMathAsText
\cs_new_protected_nopar:Npn \@@_declare_math_as_UTF_text:n #1
  {
    \cs_if_exist:cTF {#1}
      {
        \cs_new_eq:cc { keepmathUTF #1 } {#1}
        \cs_gset_protected_nopar:cpx {#1}
          {
            \exp_not:N \mode_if_math:TF
              { \exp_not:c { keepmathUTF #1 } }
              { \exp_not:c { text #1 } }
          }
        \tl_put_right:Nx \l_@@_hyperref_hook_tl
          { \cs_set_eq:NN \exp_not:c {#1} \exp_not:c { text #1 } }
      }
      { \cs_new_nopar:cpx {#1} { \exp_not:c { text #1 } } }
  }
\tl_new:N \l_@@_hyperref_hook_tl
\AtBeginDocument
  {
    \cs_if_free:NF \pdfstringdefDisableCommands
      { \pdfstringdefDisableCommands { \l_@@_hyperref_hook_tl } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal,pTF]{\@@_glyph_if_exist:n}
% 判断字符在当前字体中是否存在。
%    \begin{macrocode}
\prg_new_conditional:Npnn \@@_glyph_if_exist:n #1 { p , T , F , TF }
  {
    \etex_iffontchar:D \tex_font:D \etex_numexpr:D #1 \scan_stop:
      \prg_return_true: \else: \prg_return_false: \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\UndeclareUTFcharacter}
% 取消编码 |#1| 下的符号命令 |#3|。
%    \begin{macrocode}
\RenewDocumentCommand \UndeclareUTFcharacter { O { \UTFencname } m m }
  {
    \@@_if_csname:nTF {#3}
      { \UndeclareTextCommand {#3} }
      { \exp_args:Nc \UndeclareTextCommand { \tl_to_str:n {#3} } }
      {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\UndeclareUTFcomposite}
% 取消编码 |#1| 下的复合符号命令 |#3{#4}|。
%    \begin{macrocode}
\RenewDocumentCommand \UndeclareUTFcomposite { O { \UTFencname } m m m }
  {
    \@@_if_csname:nTF {#3}
      { \@@_undeclare_composite:Nnnn #3 }
      { \exp_args:Nc \@@_undeclare_composite:Nnnn { \tl_to_str:n {#3} } }
      {#1} {#4} {#2}
  }
\cs_new_protected:Npn \@@_undeclare_composite:Nnnn #1#2#3#4
  { \cs_undefine:c { \@@_composite_cs:Nnn #1 {#2} {#3} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_composite_cs:Nnn,\@@_composite_cs:nnn}
%    \begin{macrocode}
\cs_new:Npx \@@_composite_cs:Nnn #1#2#3
  { \cs_to_str:N \\ #2 \exp_not:N \token_to_str:N #1 - \exp_not:N \tl_to_str:n {#3} }
\cs_new:Npx \@@_composite_cs:nnn #1#2#3
  { \cs_to_str:N \\ #2 #1 - \exp_not:N \tl_to_str:n {#3} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_if_csname:nTF}
% 判断 |#1| 是否可以作为控制序列的名字。这是因为 \pkg{xunicide} 使用了下面的定义。
% \begin{verbatim}
%   \DeclareUTFcharacter[\UTFencname]{x0149}{'n}
% \end{verbatim}
%    \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_csname:n #1 { TF }
  {
    \tl_if_single_token:nTF {#1}
      {
        \if_predicate:w
          \bool_if_p:n { \token_if_cs_p:N #1 || \token_if_active_p:N #1 }
          \prg_return_true: \else: \prg_return_false: \fi:
      }
      { \prg_return_false: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFcharacter}
% 定义编码 |#1| 下的符号命令 |#3|，其对应符号的 Unicode 是 |#2|。
%    \begin{macrocode}
\RenewDocumentCommand \DeclareUTFcharacter { O { \UTFencname } m m }
  {
    \str_if_eq:nnTF {#3} { \hbar }
      { \@@_restore_hbar: }
      {
        \@@_if_csname:nTF {#3}
          { \@@_declare_character:Nnn #3 }
          { \@@_declare_character:cnn { \tl_to_str:n {#3} } }
        {#1} {#2}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_restore_hbar:}
% 恢复 \tn{hbar} 为原本定义。
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_restore_hbar:
  {
    \cs_if_free:cF { ? - \token_to_str:N \hbar }
      { \@@_restore_hbar:c { ? - \token_to_str:N \hbar } }
  }
\cs_new_protected_nopar:Npn \@@_restore_hbar:N #1
  {
    \cs_gset_eq:NN \hbar #1
    \cs_undefine:N #1
  }
\cs_generate_variant:Nn \@@_restore_hbar:N { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_declare_character:Nnn}
% 通过 \texttt{lowercase} 技巧，直接由 Unicode |#3| 得到编码 |#2| 下的符号命令
% |#1| 对应的实际字符。\tn{DeclareUTFSymbol} 的参数格式与 \tn{DeclareTextSymbol}
% 完全一致。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_declare_character:Nnn #1#2#3
  {
    \@@_provide_text_command_default:N #1
    \group_begin:
    \char_set_lccode:nn { `0 } { \@@_check_slot:n {#3} }
    \tl_to_lowercase:n
      {
        \group_end:
        \@@_declare_character:NNxn 0
      }
      #1 { \token_to_str:N #1 } {#2}
  }
\cs_generate_variant:Nn \@@_declare_character:Nnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFSymbol,\DeclareUTFCommand}
% \tn{DeclareUTFCommand} 只能用于定义不带参数的符号命令。
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFSymbol { m O { \UTFencname } m }
  { \@@_declare_character:Nnn #1 {#2} {#3} }
\NewDocumentCommand \DeclareUTFCommand { m O { \UTFencname } m }
  { \@@_text_command:Nonn #1 { \token_to_str:N #1 } {#2} {#3} }
\cs_new_protected:Npn \@@_text_command:Nnnn #1#2#3#4
  { \DeclareTextCommand #1 {#3} { \@@_text_command:nn {#2} {#4} } }
\cs_generate_variant:Nn \@@_text_command:Nnnn { No }
\cs_new_protected:Npn \@@_text_command:nn #1#2
  {
    \@@_begin_hook:nn {#1} {#2}
    #2
    \@@_end_hook:nn {#1} {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_provide_text_command_default:N}
% 如果控制序列 |#1| 已经存在，但不是符号命令，\pkg{xunicode} 会将它定义为
% \tn{UTFencname} 编码下的符号命令。但是编码被转换之后，再使用这些控制序列，
% \pkg{NFSS} 就会报错。为此需要给出这些符号命令的默认定义，与原来的意义相同。
% 这些命令包括
% \begin{verbatim}
%   \nobreakspace   macro:->\protect \nobreakspace
%   \copyright      macro:->\protect \copyright
%   \AA             macro:->\r A
%   \aa             macro:->\r a
%   \textrhookopeno \long macro:->\textrethookbelow {\textopeno }
%   \hbar           macro:->{\mathchar '26\mkern -9muh}
%   \textaolig      macro:->{a\kern -.25em o}
% \end{verbatim}
% 影响比较大的是 \tn{nobreakspace}、\tn{copyright} 和 \tn{hbar}。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_provide_text_command_default:N #1
  {
    \bool_if:nF
      {
        \cs_if_exist_p:c { ?   \token_to_str:N #1 } ||
        \cs_if_free_p:c  { ? - \token_to_str:N #1 }
      }
      { \exp_args:NNv \ProvideTextCommandDefault #1 { ? - \token_to_str:N #1 } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_declare_character:NNnn}
% 使用编码 |#4| 下的符号命令 |#2| 的时候先判断它对应的实际字符 |#1| 在当前字体中
% 是否存在。如果不存在则转换到 \tn{DeclareTextSymbolDefault} 中设置的编码或者使用
% \cs{Declare\-Text\-Command\-Default} 中设置的命令。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_declare_character:NNnn #1#2#3#4
  { \DeclareTextCommand #2 {#4} { \@@_text_character:nN {#3} {#1} } }
\cs_new_protected:Npn \@@_text_character:nN #1#2
  {
    \@@_begin_hook:nn {#1} {#2}
    \@@_glyph_if_exist:nTF { `#2 }
      {#2} { \cs_if_exist_use:cF { ? #1 } {#2} }
    \@@_end_hook:nn {#1} {#2}
  }
\cs_generate_variant:Nn \@@_declare_character:NNnn { NNx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_check_slot:n}
% \pkg{xunicode} 中使用的 Unicode 格式是诸如 |x0022| 的形式，这就需要一些转换。
%    \begin{macrocode}
\cs_new_nopar:Npn \@@_check_slot:n #1
  {
    \int_eval:n
      {
        \tl_if_head_eq_charcode:nNTF {#1} x
          { " \use_none:n #1 } {#1}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFcomposite}
% 设置编码 |#1| 下的符号命令 |#3| 与它的参数 |#4| 的复合对应的符号的 Unicode 是 |#2|。
%    \begin{macrocode}
\RenewDocumentCommand \DeclareUTFcomposite { O { \UTFencname } m m m }
  {
    \@@_if_csname:nTF {#3}
      { \@@_declare_composite:Nnnn #3 }
      { \@@_declare_composite:cnnn { \tl_to_str:n {#3} } }
      {#1} {#4} {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_declare_composite:Nnnn}
% 这里使用 \cs{tex_afterassignment:D} 是因为 \pkg{xunicode} 有如下的定义。
% \begin{verbatim}
%   \DeclareUTFcomposite[\UTFencname]{x02E8\char"02E5}{\tonebar}{25}
%   \DeclareUTFcomposite[\UTFencname]{x02E5\char"02E8}{\tonebar}{52}
% \end{verbatim}
% 对复合符号命令的定义用的是 \tn{chardef}，这有利于下面字符是否存在的判断。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_declare_composite:Nnnn #1#2#3#4
  {
    \tex_afterassignment:D \use_none_delimit_by_q_stop:w
    \@@_chardef:cn { \@@_composite_cs:Nnn #1 {#2} {#3} }
      { \@@_check_slot:n {#4} }
    \q_stop
  }
\cs_new_protected:Npn \@@_chardef:Nn #1#2
  { \tex_chardef:D #1 = \etex_numexpr:D #2 \scan_stop: }
\cs_generate_variant:Nn \@@_chardef:Nn { c }
\cs_generate_variant:Nn \@@_declare_composite:Nnnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFCompositeCommand}
% 设置编码 |#2| 下的符号命令 |#1| 与它的参数 |#3| 的复合对应结果是 |#4|。不能直接用
% \cs{Declare\-Text\-Composite\-Command} 来定义，它与我们的机制冲突。
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFCompositeCommand { m O { \UTFencname } m m }
  { \cs_set_protected:cpn { \@@_composite_cs:Nnn #1 {#2} {#3} } {#4} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFCompositeSymbol}
% 设置编码 |#2| 下的符号命令 |#1| 与它的参数 |#3| 的复合对应结果是 |#4|。不能直接用
% \cs{Declare\-Text\-Composite} 来定义，它与我们的机制冲突。
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFCompositeSymbol { m O { \UTFencname } m m }
  {
    \@@_chardef:cn { \@@_composite_cs:Nnn #1 {#2} {#3} }
      { \@@_check_slot:n {#4} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFComposite}
% 将 |#1| 设置为编码 |#2| 下的带一个参数的复合符号命令。
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFComposite { m O { \UTFencname } }
  { \use:x { \@@_declare_composite:Nnn \exp_not:N #1 { \token_to_str:N #1 } {#2} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFEncodedAccent}
% |#1| 是重音命令，|#2| 是编码，|#3| 是组合重音符号的 Unicode，|#4| 是基本重音符号
% 的 Unicode。当 |#1| 的参数为空时，输出 |#4|，否则是 |#1| 的参数与 |#3| 的组合。
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFEncodedAccent { m O { \UTFencname } m m }
  { \@@_declare_encoded:NNnnn \@@_combine_accent:nnNNn #1 {#2} {#3} {#4} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFEncodedAccents}
% |#1| 是重音命令，|#2| 是编码，|#3| 和 |#4| 都是组合重音符号的 Unicode。
% 输出 |#1| 与 |#3|、|#4| 的组合。
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFEncodedAccents { m O { \UTFencname } m m }
  { \@@_declare_encoded:NNnnn \@@_combine_accents:nnNNn #1 {#2} {#3} {#4} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFEncodedSymbol}
% |#1| 是带参数的符号命令，|#2| 是编码，|#3| 是组合符号的 Unicode，|#4| 是基本符号的
% Unicode。当 |#1| 的参数为空时，输出 |#4|，否则是 |#1| 的参数与 |#3| 的组合。
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFEncodedSymbol { m O { \UTFencname } m m }
  { \@@_declare_encoded:NNnnn \@@_combine_symbol:nnNNn #1 {#2} {#3} {#4} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFEncodedCircle}
% |#1| 是带参数的圆圈符号命令，|#2| 是编码，|#3| 是组合圆圈符号的 Unicode，|#4|
% 是圆圈符号的 Unicode。当 |#1| 的参数为空时，输出 |#4|，否则是 |#1| 的参数与 |#4| 的组合。
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFEncodedCircle { m O { \UTFencname } m m }
  { \@@_declare_encoded:NNnnn \@@_combine_circle:nnNNn #1 {#2} {#3} {#4} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareEncodedCompositeCharacter}
%    \begin{macrocode}
\RenewDocumentCommand \DeclareEncodedCompositeCharacter { m m m m }
  { \DeclareUTFEncodedSymbol #2 [#1] { "#3 } { "0#4 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareEncodedCompositeAccents}
% \changes{v3.2.9}{2013/12/07}{修正 \pkg{xunicode} 中的错误定义。}
%    \begin{macrocode}
\RenewDocumentCommand \DeclareEncodedCompositeAccents { m m m m }
  { \DeclareUTFEncodedAccents #2 [#1] { "#4 } { "#3 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFDoubleEncodedAccent}
% \changes{v3.2.10}{2014/02/20}{改进 \tn{t} 等的定义方式。}
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFDoubleEncodedAccent { m O { \UTFencname } m m }
  { \@@_declare_encoded:NNnnn \@@_combine_double_accent:nnNNn #1 {#2} {#3} {#4} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFDoubleEncodedSymbol}
% \changes{v3.2.10}{2014/02/21}{改进 \tn{sliding} 等的定义方式。}
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFDoubleEncodedSymbol { m O { \UTFencname } m m }
  { \@@_declare_encoded:NNnnn \@@_combine_double_symbol:nnNNn #1 {#2} {#3} {#4} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_declare_composite:Nnn}
% 通过 \texttt{lowercase} 技巧，直接由重音符号的 Unicode 得到实际字符。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_declare_composite:Nnn #1#2#3
  { \DeclareTextCommand #1 {#3} { \@@_text_composite:nnn {#2} {#3} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_text_composite:nnn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_text_composite:nnn #1#2#3
  {
    \@@_begin_hook:nn {#1} {#3}
    \cs_if_exist:cTF { \@@_composite_cs:nnn {#1} {#2} {#3} }
      {
        \@@_text_composite:cnn
          { \@@_composite_cs:nnn {#1} {#2} {#3} } {#1} {#3}
      }
      { \cs_if_exist_use:cTF { ? #1 } { {#3} } {#3} }
    \@@_end_hook:nn {#1} {#3}
  }
\cs_new_protected:Npn \@@_text_composite:Nnn #1#2#3
  {
    \token_if_chardef:NTF #1
      {
        \@@_glyph_if_exist:nTF {#1}
          {#1} { \cs_if_exist_use:cTF { ? #2 } { {#3} } {#3} }
      }
      {#1}
  }
\cs_generate_variant:Nn \@@_text_composite:Nnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_declare_encoded:NNnnn}
% 通过 \texttt{lowercase} 技巧，直接由重音符号的 Unicode 得到实际字符。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_declare_encoded:NNnnn #1#2#3#4#5
  {
    \group_begin:
    \char_set_lccode:nn { `4 } { \@@_check_slot:n {#4} }
    \char_set_lccode:nn { `5 } { \@@_check_slot:n {#5} }
    \tl_to_lowercase:n
      {
        \group_end:
        \@@_declare_encoded:NNNNxx 4 5
      }
      #1 #2 { \token_to_str:N #2 } {#3}
  }
\cs_new_protected:Npn \@@_declare_encoded:NNNNnn #1#2#3#4#5#6
  { \DeclareTextCommand #4 {#6} { #3 {#5} {#6} {#1} {#2} } }
\cs_generate_variant:Nn \@@_declare_encoded:NNnnn { c }
\cs_generate_variant:Nn \@@_declare_encoded:NNNNnn { NNNNxx }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_text_combine:NnnNNn}
% 若重音命令 |#2| 与它的参数 |#6| 的复合已经由 \tn{DeclareUTFcomposite} 设置，
% 并且在当前字体中存在该字符，则直接使用。否则使用组合命令。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_text_combine:NnnNNn #1#2#3#4#5#6
  {
    \@@_begin_hook:nn {#2} {#6}
    \cs_if_exist:cTF { \@@_composite_cs:nnn {#2} {#3} {#6} }
      {
        \@@_text_combine:cNnNNn
          { \@@_composite_cs:nnn {#2} {#3} {#6} } #1 {#2} {#4} {#5} {#6}
      }
      { #1 {#6} {#2} {#4} {#5} }
    \@@_end_hook:nn {#2} {#6}
  }
\cs_new_protected:Npn \@@_text_combine:NNnNNn #1#2#3#4#5#6
  {
    \token_if_chardef:NTF #1
      { \@@_glyph_if_exist:nTF {#1} {#1} { #2 {#6} {#3} {#4} {#5} } }
      {#1}
  }
\cs_generate_variant:Nn \@@_text_combine:NNnNNn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_combine_symbol:nnNNn}
%     \begin{macrocode}
\cs_new_protected:Npn \@@_combine_symbol:nnNNn
  { \@@_text_combine:NnnNNn \@@_add_symbol:nnNN }
\cs_new_protected:Npn \@@_add_symbol:nnNN #1#2#3#4
  {
    \tl_if_blank:nTF {#1}
      {
        \@@_glyph_if_exist:nTF { `#4 }
          {#4}
          { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} }
      }
      {
        \@@_glyph_if_exist:nTF { `#3 }
          { #1#3 }
          { \cs_if_exist_use:cTF { ? #2 } { {#1} } { #1#3 } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_combine_accent:nnNNn,\@@_add_accent:nnNN}
% 若组合重音符号的 |#3| 和基本重音符号 |#4| 在当前字体中都不存在，则转换到
% \cs{Declare\-Text\-Accent\-Default} 设置的编码或者使用
% \tn{DeclareTextCommandDefault} 中设置的命令。\texttt{0.9999} 版以前的 \XeTeX
% 需要设置 \tn{XeTeXinputnormalization} 为 $1$，才能使用字体中由基础字符和组合符号
% 对应的实际字符；而 \texttt{0.9999} 版以后的 \XeTeX 默认就启用这个功能，^^A
% \tn{XeTeXinputnormalization} 似乎是无效的，怀疑是使用 HarfBuzz 库替代 ICU 进行
% 字体排版的缘故\footnote{\url{http://tug.org/pipermail/xetex/2013-July/024579.html}}。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_combine_accent:nnNNn
  { \@@_text_combine:NnnNNn \@@_add_accent:nnNN }
\cs_new_protected:Npn \@@_add_accent:nnNN #1#2#3#4
  {
    \tl_if_blank:nTF {#1}
      {
        \@@_glyph_if_exist:nTF { `#4 }
          {#4}
          { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} }
      }
      {
        \@@_glyph_if_exist:nTF { `#3 }
          { #1#3 }
          {
            \@@_glyph_if_exist:nTF { `#4 }
              { \add@accent { `#4 } {#1} }
              { \cs_if_exist_use:cTF { ? #2 } { {#1} } { #1#3 } }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_combine_accents:nnNNn,\@@_add_accents:nnNN}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_combine_accents:nnNNn
  { \@@_text_combine:NnnNNn \@@_add_accents:nnNN }
\cs_new_protected:Npn \@@_add_accents:nnNN #1#2#3#4
  {
    \tl_if_blank:nTF {#1}
      { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#1} }
      {
        \bool_if:nTF
          {
            \@@_glyph_if_exist_p:n { `#3 } &&
            \@@_glyph_if_exist_p:n { `#4 }
          }
          { #1#3#4 }
          { \cs_if_exist_use:cTF { ? #2 } { {#1} } { #1#3#4 } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_combine_circle:nnNNn,\@@_add_circle:nnNN,\@@_add_circle:nN}
% 对圆圈中的数字或者字母适当缩小，以适合圆圈的大小。只有字体中存在
% \texttt{U+25EF} 时，才使用这里的设置，否则还还是 \LaTeX\ 中的设置。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_combine_circle:nnNNn
  { \@@_text_combine:NnnNNn \@@_add_circle:nnNN }
\cs_new_protected:Npn \@@_add_circle:nnNN #1#2#3#4
  {
    \tl_if_blank:nTF {#1}
      {
        \@@_glyph_if_exist:nTF { `#4 }
          {#4}
          { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} }
      }
      {
        \@@_glyph_if_exist:nTF { `#4 }
          { \@@_add_circle:nN {#1} #4 }
          { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#1} }
      }
  }
\cs_new_protected:Npn \@@_add_circle:nN #1#2
  {
    \hcoffin_set:Nn \l_@@_tmp_coffin {#1}
    \hcoffin_set:Nn \l_@@_circle_coffin {#2}
    \fp_set:Nn \l_@@_circle_scale_fp
      {
        \dim_to_decimal_in_unit:nn
          {
            \fp_use:N \l_@@_circle_ratio_fp
            \coffin_wd:N \l_@@_circle_coffin
          }
          { \coffin_wd:N \l_@@_tmp_coffin }
      }
    \coffin_scale:Nnn \l_@@_tmp_coffin
      { \l_@@_circle_scale_fp } { \l_@@_circle_scale_fp }
    \coffin_attach:NnnNnnnn
      \l_@@_circle_coffin { hc } { vc }
      \l_@@_tmp_coffin    { hc } { vc } { \c_zero_dim } { \c_zero_dim }
    \coffin_typeset:Nnnnn \l_@@_circle_coffin
      { H } { l } { \c_zero_dim } { \c_zero_dim }
  }
\fp_new:N \l_@@_circle_scale_fp
\coffin_new:N \l_@@_tmp_coffin
\coffin_new:N \l_@@_circle_coffin
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\settextcircledratio}
% 设置圆圈中文字的宽度与圆圈宽度的比例，预设为 \texttt{0.7}。
%    \begin{macrocode}
\NewDocumentCommand \settextcircledratio { m }
  { \fp_set:Nn \l_@@_circle_ratio_fp {#1} }
\fp_new:N \l_@@_circle_ratio_fp
\settextcircledratio { 0.7 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_combine_double_accent:nnNNn}
% 使 \tn{t} 等组合重音符号放在参数的第一个字母的右边。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_combine_double_accent:nnNNn
  { \@@_text_combine:NnnNNn \@@_add_double_accent:nnNN }
\cs_new_protected:Npn \@@_add_double_accent:nnNN #1#2#3#4
  {
    \tl_if_blank:nTF {#1}
      {
        \@@_glyph_if_exist:nTF { `#4 }
          {#4}
          { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} }
      }
      {
        \@@_glyph_if_exist:nTF { `#3 }
          { \@@_add_double_symbol:nN {#1} #3 }
          {
            \@@_glyph_if_exist:nTF { `#4 }
              { \add@accent { `#4 } {#1} }
              { \cs_if_exist_use:cTF { ? #2 } { {#1} } { #1#3 } }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_combine_double_symbol:nnNNn}
% 使 \tn{sliding} 等组合重音符号放在参数的第一个字母的右边。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_combine_double_symbol:nnNNn
  { \@@_text_combine:NnnNNn \@@_add_double_symbol:nnNN }
\cs_new_protected:Npn \@@_add_double_symbol:nnNN #1#2#3#4
  {
    \tl_if_blank:nTF {#1}
      {
        \@@_glyph_if_exist:nTF { `#4 }
          {#4}
          { \cs_if_exist_use:cTF { ? #2 } { {#1} } {#4} }
      }
      {
        \@@_glyph_if_exist:nTF { `#3 }
          { \@@_add_double_symbol:nN {#1} #3 }
          { \cs_if_exist_use:cTF { ? #2 } { {#1} } { #1#3 } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_add_double_symbol:nN}
% 如果参数的第一个记号是字母类、其它符号类或者由 \tn{chardef} 定义，则将组合符号
% 放在它的右边，否则不作处理。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_add_double_symbol:nN #1#2
  {
    \tl_if_head_is_N_type:nTF {#1}
      {
        \exp_after:wN \exp_after:wN \exp_after:wN
        \@@_add_double_symbol_aux:NnN \exp_after:wN \exp_after:wN
          \tl_head:w #1 \q_stop \exp_after:wN { \use_none:n #1 } #2
      }
      { #1#2 }
  }
\cs_new_protected:Npn \@@_add_double_symbol_aux:NnN #1#2#3
  {
    \bool_if:nTF
      {
        \token_if_letter_p:N #1 ||
        \token_if_other_p:N #1  ||
        \token_if_chardef_p:N #1
      }
      { #1#3#2 }
      { #1#2#3 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\AtBeginUTFCommand,\AtEndUTFCommand}
% 设置在符号命令前后使用的钩子，可选参数用于指定单个符号命名。可以用 |#1|
% 引用带参数的组合符号命令的参数或者符号命令对应的符号。
% \changes{v3.2.6}{2013/08/15}{可以指定特定符号命令使用的钩子。}
%    \begin{macrocode}
\NewDocumentCommand \AtBeginUTFCommand { s O { } +m }
  {
    \tl_if_blank:nTF {#2}
      {
        \IfBooleanTF {#1}
          { \tl_set:Nn \l_@@_begin_hook_tl {#3} }
          { \tl_put_right:Nn \l_@@_begin_hook_tl {#3} }
      }
      { \@@_set_cmd_hook:nnn { begin } {#2} {#3} }
  }
\NewDocumentCommand \AtEndUTFCommand { s O { } +m }
  {
    \tl_if_blank:nTF {#2}
      {
        \IfBooleanTF {#1}
          { \tl_set:Nn \l_@@_end_hook_tl {#3} }
          { \tl_put_right:Nn \l_@@_end_hook_tl {#3} }
      }
      { \@@_set_cmd_hook:nnn { end } {#2} {#3} }
  }
\tl_new:N \l_@@_begin_hook_tl
\tl_new:N \l_@@_end_hook_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_set_cmd_hook:nnn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_cmd_hook:nnn #1#2#3
  {
    \cs_set_protected:cpn
      {
        \tl_if_single:nTF {#2}
          { \use:c { @@_#1_csname:n } { \token_to_str:N #2 } }
          { \@@_set_cmd_hook_aux:Nnwn #2 \q_stop {#1} }
      } ##1
      {#3}
  }
\cs_new:Npn \@@_set_cmd_hook_aux:Nnwn #1#2 \q_stop #3
  { \use:c { @@_#3_csname:n } { \token_to_str:N #1 - \tl_to_str:n {#2} } }
\cs_new_nopar:Npn \@@_begin_csname:n #1 { @@_begin_#1_hook:n }
\cs_new_nopar:Npn \@@_end_csname:n #1   { @@_end_#1_hook:n }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\@@_begin_hook:nn,\@@_end_hook:nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_begin_hook:nn #1#2
  {
    \tl_use:N \l_@@_begin_hook_tl
    \cs_if_exist_use:cF { \@@_begin_csname:n { #1 - \tl_to_str:n {#2} } }
      { \cs_if_exist_use:cF { \@@_begin_csname:n {#1} } { \use_none:n } }
      {#2}
  }
\cs_new_protected:Npn \@@_end_hook:nn #1#2
  {
    \cs_if_exist_use:cF { \@@_end_csname:n { #1 - \tl_to_str:n {#2} } }
      { \cs_if_exist_use:cF { \@@_end_csname:n {#1} } { \use_none:n } }
      {#2}
    \tl_use:N \l_@@_end_hook_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\DeclareUTFTIPACommand}
% \changes{v3.2.10}{2014/02/20}{检查 \tn{t} 和 \tn{sliding} 的参数是否以 \tn{textipa} 开头。}
%    \begin{macrocode}
\NewDocumentCommand \DeclareUTFTIPACommand { O { \UTFencname } m }
  { \use:x { \@@_text_tipa_command:Nnn \exp_not:N #2 { \token_to_str:N #2 } {#1} } }
\cs_new_protected:Npn \@@_text_tipa_command:Nnn #1#2#3
  {
    \cs_set_eq:cc { UTF/#3#2 } { #3#2 }
    \DeclareTextCommand #1 {#3} { \@@_text_tipa_command:nnn {#3} {#2} }
  }
\cs_new_protected:Npn \@@_text_tipa_command:nnn #1#2#3
  {
    \exp_after:wN \@@_check_for_tipa:NNn
      \cs:w \use_none:n #2 \exp_after:wN \cs_end:
      \cs:w UTF/#1#2 \cs_end: {#3}
  }
\cs_new_protected:Npn \@@_check_for_tipa:NNn #1#2#3
  {
    \tl_if_head_eq_meaning:nNTF {#3} \textipa
      {
        \exp_after:wN \tipacatchonechar \exp_after:wN
          { \exp_after:wN #1 \use_none:n #3 }
      }
      { #2 {#3} }
  }
%    \end{macrocode}
% \end{macro}
%
% \changes{v3.2.8}{2013/12/05}{启用 \pkg{xunicode} 中的带圈数字和字母设置。}
%
%    \begin{macrocode}
%</xunicode>
%<*xunextra>
%    \end{macrocode}
%
% 以下内容选自 \pkg{xunicode}，并做了适当修改。
%    \begin{macrocode}
\DeclareUTFComposite\textsuperscript
\DeclareUTFComposite\textsubscript
\DeclareUTFEncodedAccent\textsbleftarrow{"20EE}{"20FF}
\DeclareUTFEncodedAccent\`{"0300}{"02CB}
\DeclareUTFEncodedAccent\capitalgrave{"0300}{"02CB}
\DeclareUTFEncodedAccent\'{"0301}{"02CA}
\DeclareUTFEncodedAccent\capitalacute{"0301}{"02CA}
\DeclareUTFEncodedAccent\^{"0302}{"02C6}
\DeclareUTFEncodedAccent\capitalcircumflex{"0302}{"02C6}
\DeclareUTFEncodedAccent\~{"0303}{"02DC}
\DeclareUTFEncodedAccent\capitaltilde{"0303}{"02DC}
\DeclareUTFEncodedAccent\={"0304}{"02C9}
\DeclareUTFEncodedAccent\capitalmacron{"0304}{"02C9}
\DeclareUTFEncodedAccent\textoverline{"0305}{"203E}
\DeclareUTFEncodedAccent\u{"0306}{"02D8}
\DeclareUTFEncodedAccent\capitalbreve{"0306}{"02D8}
\DeclareUTFEncodedAccent\.{"0307}{"02D9}
\DeclareUTFEncodedAccent\capitaldotaccent{"0307}{"02D9}
\DeclareUTFEncodedAccent\"{"0308}{"00A8}
\DeclareUTFEncodedAccent\capitaldieresis{"0308}{"00A8}
\DeclareUTFEncodedAccent\m{"0309}{"0309}
\DeclareUTFEncodedAccent\texthookabove{"0309}{"0309}
\DeclareUTFEncodedAccent\r{"030A}{"02DA}
\DeclareUTFEncodedAccent\capitalring{"030A}{"02DA}
\DeclareUTFEncodedAccent\H{"030B}{"02DD}
\DeclareUTFEncodedAccent\capitalhungarumlaut{"030B}{"02DD}
\DeclareUTFEncodedAccent\v{"030C}{"02C7}
\DeclareUTFEncodedAccent\capitalcaron{"030C}{"02C7}
\DeclareUTFEncodedAccent\textvbaraccent{"030D}{"02C8}
\DeclareUTFEncodedAccent\textdoublevbaraccent{"030E}{"0022}
\DeclareUTFEncodedAccent\U{"030E}{"0022}
\DeclareUTFEncodedAccent\textdoublegrave{"030F}{"02F5}
\DeclareUTFEncodedAccent\G{"030F}{"02F5}
\DeclareUTFEncodedAccent\textdotbreve{"0310}{"0310}
\DeclareUTFEncodedAccent\textroundcap{"0311}{"0311}
\DeclareUTFEncodedAccent\newtie{"0311}{"0311}
\DeclareUTFEncodedAccent\capitalnewtie{"0311}{"0311}
\DeclareUTFEncodedAccent\textturncommaabove{"0312}{"02BB}
\DeclareUTFEncodedAccent\textcommaabove{"0313}{"02BC}
\DeclareUTFEncodedAccent\textrevcommaabove{"0314}{"02BD}
\DeclareUTFEncodedAccent\overbridge{"0346}{"0346}
\DeclareUTFEncodedAccent\crtilde{"034A}{"034A}
\DeclareUTFEncodedAccent\dottedtilde{"034B}{"034B}
\DeclareUTFEncodedAccent\doubletilde{"034C}{"034C}
\DeclareUTFEncodedAccent\textrightarrowhead{"0350}{"02C3}
\DeclareUTFEncodedAccent\textlefthalfring{"0351}{"02D3}
\DeclareUTFEncodedAccent\textrighthalfring{"0357}{"02D2}
\DeclareUTFDoubleEncodedSymbol\textdoublebrevebelow{"035C}{"035C}
\DeclareUTFDoubleEncodedAccent\textdoublebreve{"035D}{"035D}
\DeclareUTFDoubleEncodedAccent\textdoublemacron{"035E}{"035E}
\DeclareUTFDoubleEncodedSymbol\textdoublemacronbelow{"035F}{"035F}
\DeclareUTFDoubleEncodedAccent\textdoubletilde{"0360}{"0360}
\DeclareUTFDoubleEncodedAccent\t{"0361}{"0361}
\DeclareUTFDoubleEncodedAccent\capitaltie{"0361}{"0361}
\DeclareUTFDoubleEncodedAccent\texttoptiebar{"0361}{"0361}
\DeclareUTFDoubleEncodedSymbol\sliding{"0362}{"0362}
\DeclareUTFTIPACommand\t
\DeclareUTFTIPACommand\capitaltie
\DeclareUTFTIPACommand\texttoptiebar
\DeclareUTFTIPACommand\sliding
\DeclareUTFEncodedAccent\texthighrise{"1DC4}{"1DC4}
\DeclareUTFEncodedAccent\textlowrise{"1DC5}{"1DC5}
\DeclareUTFEncodedAccent\textrisefall{"1DC8}{"1DC8}
\DeclareUTFEncodedAccent\textfallrise{"1DC9}{"1DC9}
\DeclareUTFEncodedAccent\textaolig{"1DD5}{"1DD5}
\DeclareUTFCompositeSymbol\textundertie{H}{"1E2A}
\DeclareUTFCompositeSymbol\textundertie{h}{"1E2B}
\DeclareUTFEncodedAccents\textcircumgrave{"0302}{"0301}
\DeclareUTFSymbol\textFinv{"2132}
\DeclareUTFSymbol\textaleph{"2135}
\DeclareUTFSymbol\textbeth{"2136}
\DeclareUTFSymbol\textgimel{"2137}
\DeclareUTFSymbol\textdaleth{"2138}
\DeclareUTFSymbol\textGame{"2141}
\DeclareUTFCompositeCommand\tonebar{25}{\tonebar{2}\tonebar{5}}
\DeclareUTFCompositeCommand\tonebar{52}{\tonebar{5}\tonebar{2}}
\DeclareUTFSymbol\textbigcircle{"25EF}
\DeclareUTFEncodedCircle\textcircled{"20DD}{"25EF}
\DeclareUTFCompositeSymbol\textcircled{0}{"24EA}
\DeclareUTFCompositeSymbol\textcircled{1}{"2460}
\DeclareUTFCompositeSymbol\textcircled{2}{"2461}
\DeclareUTFCompositeSymbol\textcircled{3}{"2462}
\DeclareUTFCompositeSymbol\textcircled{4}{"2463}
\DeclareUTFCompositeSymbol\textcircled{5}{"2464}
\DeclareUTFCompositeSymbol\textcircled{6}{"2465}
\DeclareUTFCompositeSymbol\textcircled{7}{"2466}
\DeclareUTFCompositeSymbol\textcircled{8}{"2467}
\DeclareUTFCompositeSymbol\textcircled{9}{"2468}
\DeclareUTFCompositeSymbol\textcircled{10}{"2469}
\DeclareUTFCompositeSymbol\textcircled{11}{"246A}
\DeclareUTFCompositeSymbol\textcircled{12}{"246B}
\DeclareUTFCompositeSymbol\textcircled{13}{"246C}
\DeclareUTFCompositeSymbol\textcircled{14}{"246D}
\DeclareUTFCompositeSymbol\textcircled{15}{"246E}
\DeclareUTFCompositeSymbol\textcircled{16}{"246F}
\DeclareUTFCompositeSymbol\textcircled{17}{"2470}
\DeclareUTFCompositeSymbol\textcircled{18}{"2471}
\DeclareUTFCompositeSymbol\textcircled{19}{"2472}
\DeclareUTFCompositeSymbol\textcircled{20}{"2473}
\DeclareUTFCompositeSymbol\textcircled{21}{"3251}
\DeclareUTFCompositeSymbol\textcircled{22}{"3252}
\DeclareUTFCompositeSymbol\textcircled{23}{"3253}
\DeclareUTFCompositeSymbol\textcircled{24}{"3254}
\DeclareUTFCompositeSymbol\textcircled{25}{"3255}
\DeclareUTFCompositeSymbol\textcircled{26}{"3256}
\DeclareUTFCompositeSymbol\textcircled{27}{"3257}
\DeclareUTFCompositeSymbol\textcircled{28}{"3258}
\DeclareUTFCompositeSymbol\textcircled{29}{"3259}
\DeclareUTFCompositeSymbol\textcircled{30}{"325A}
\DeclareUTFCompositeSymbol\textcircled{31}{"325B}
\DeclareUTFCompositeSymbol\textcircled{32}{"325C}
\DeclareUTFCompositeSymbol\textcircled{33}{"325D}
\DeclareUTFCompositeSymbol\textcircled{34}{"325E}
\DeclareUTFCompositeSymbol\textcircled{35}{"325F}
\DeclareUTFCompositeSymbol\textcircled{36}{"32B1}
\DeclareUTFCompositeSymbol\textcircled{37}{"32B2}
\DeclareUTFCompositeSymbol\textcircled{38}{"32B3}
\DeclareUTFCompositeSymbol\textcircled{39}{"32B4}
\DeclareUTFCompositeSymbol\textcircled{40}{"32B5}
\DeclareUTFCompositeSymbol\textcircled{41}{"32B6}
\DeclareUTFCompositeSymbol\textcircled{42}{"32B7}
\DeclareUTFCompositeSymbol\textcircled{43}{"32B8}
\DeclareUTFCompositeSymbol\textcircled{44}{"32B9}
\DeclareUTFCompositeSymbol\textcircled{45}{"32BA}
\DeclareUTFCompositeSymbol\textcircled{46}{"32BB}
\DeclareUTFCompositeSymbol\textcircled{47}{"32BC}
\DeclareUTFCompositeSymbol\textcircled{48}{"32BD}
\DeclareUTFCompositeSymbol\textcircled{49}{"32BE}
\DeclareUTFCompositeSymbol\textcircled{50}{"32BF}
\DeclareUTFCompositeSymbol\textcircled{A}{"24B6}
\DeclareUTFCompositeSymbol\textcircled{B}{"24B7}
\DeclareUTFCompositeSymbol\textcircled{C}{"24B8}
\DeclareUTFCompositeSymbol\textcircled{D}{"24B9}
\DeclareUTFCompositeSymbol\textcircled{E}{"24BA}
\DeclareUTFCompositeSymbol\textcircled{F}{"24BB}
\DeclareUTFCompositeSymbol\textcircled{G}{"24BC}
\DeclareUTFCompositeSymbol\textcircled{H}{"24BD}
\DeclareUTFCompositeSymbol\textcircled{I}{"24BE}
\DeclareUTFCompositeSymbol\textcircled{J}{"24BF}
\DeclareUTFCompositeSymbol\textcircled{K}{"24C0}
\DeclareUTFCompositeSymbol\textcircled{L}{"24C1}
\DeclareUTFCompositeSymbol\textcircled{M}{"24C2}
\DeclareUTFCompositeSymbol\textcircled{N}{"24C3}
\DeclareUTFCompositeSymbol\textcircled{O}{"24C4}
\DeclareUTFCompositeSymbol\textcircled{P}{"24C5}
\DeclareUTFCompositeSymbol\textcircled{Q}{"24C6}
\DeclareUTFCompositeSymbol\textcircled{R}{"24C7}
\DeclareUTFCompositeSymbol\textcircled{S}{"24C8}
\DeclareUTFCompositeSymbol\textcircled{T}{"24C9}
\DeclareUTFCompositeSymbol\textcircled{U}{"24CA}
\DeclareUTFCompositeSymbol\textcircled{V}{"24CB}
\DeclareUTFCompositeSymbol\textcircled{W}{"24CC}
\DeclareUTFCompositeSymbol\textcircled{X}{"24CD}
\DeclareUTFCompositeSymbol\textcircled{Y}{"24CE}
\DeclareUTFCompositeSymbol\textcircled{Z}{"24CF}
\DeclareUTFCompositeSymbol\textcircled{a}{"24D0}
\DeclareUTFCompositeSymbol\textcircled{b}{"24D1}
\DeclareUTFCompositeSymbol\textcircled{c}{"24D2}
\DeclareUTFCompositeSymbol\textcircled{d}{"24D3}
\DeclareUTFCompositeSymbol\textcircled{e}{"24D4}
\DeclareUTFCompositeSymbol\textcircled{f}{"24D5}
\DeclareUTFCompositeSymbol\textcircled{g}{"24D6}
\DeclareUTFCompositeSymbol\textcircled{h}{"24D7}
\DeclareUTFCompositeSymbol\textcircled{i}{"24D8}
\DeclareUTFCompositeSymbol\textcircled{j}{"24D9}
\DeclareUTFCompositeSymbol\textcircled{k}{"24DA}
\DeclareUTFCompositeSymbol\textcircled{l}{"24DB}
\DeclareUTFCompositeSymbol\textcircled{m}{"24DC}
\DeclareUTFCompositeSymbol\textcircled{n}{"24DD}
\DeclareUTFCompositeSymbol\textcircled{o}{"24DE}
\DeclareUTFCompositeSymbol\textcircled{p}{"24DF}
\DeclareUTFCompositeSymbol\textcircled{q}{"24E0}
\DeclareUTFCompositeSymbol\textcircled{r}{"24E1}
\DeclareUTFCompositeSymbol\textcircled{s}{"24E2}
\DeclareUTFCompositeSymbol\textcircled{t}{"24E3}
\DeclareUTFCompositeSymbol\textcircled{u}{"24E4}
\DeclareUTFCompositeSymbol\textcircled{v}{"24E5}
\DeclareUTFCompositeSymbol\textcircled{w}{"24E6}
\DeclareUTFCompositeSymbol\textcircled{x}{"24E7}
\DeclareUTFCompositeSymbol\textcircled{y}{"24E8}
\DeclareUTFCompositeSymbol\textcircled{z}{"24E9}
\DeclareUTFCompositeSymbol\textsuperscript{h}{"02B0}
\DeclareUTFCompositeSymbol\textsuperscript{\texthth}{"02B1}
\DeclareUTFCompositeSymbol\textsuperscript{j}{"02B2}
\DeclareUTFCompositeSymbol\textsuperscript{r}{"02B3}
\DeclareUTFCompositeSymbol\textsuperscript{\textturnr}{"02B4}
\DeclareUTFCompositeSymbol\textsuperscript{\textturnrrtail}{"02B5}
\DeclareUTFCompositeSymbol\textsuperscript{\textinvscr}{"02B6}
\DeclareUTFCompositeSymbol\textsuperscript{w}{"02B7}
\DeclareUTFCompositeSymbol\textsuperscript{y}{"02B8}
\DeclareUTFCompositeSymbol\textsuperscript{\textbabygamma}{"02E0}
\DeclareUTFCompositeSymbol\textsuperscript{\textgammalatinsmall}{"02E0}
\DeclareUTFCompositeSymbol\textsuperscript{l}{"02E1}
\DeclareUTFCompositeSymbol\textsuperscript{s}{"02E2}
\DeclareUTFCompositeSymbol\textsuperscript{x}{"02E3}
\DeclareUTFCompositeSymbol\textsuperscript{\textrevglotstop}{"02E4}
\DeclareUTFCompositeSymbol\textsuperscript{\textrevepsilon}{"1D4C}
\DeclareUTFCompositeSymbol\textsuperscript{\cyrn}{"1D78}
\DeclareUTFCompositeSymbol\textsuperscript{\textbarsci}{"1DA7}
\DeclareUTFCompositeSymbol\textsuperscript{V}{"2C7D}
\DeclareUTFCompositeSymbol\textsuperscript{\textHbar}{"A7F8}
\DeclareUTFCompositeSymbol\textsuperscript{\textHslash}{"A7F8}
\DeclareUTFCompositeSymbol\textsuperscript{\oe}{"A7F9}
\DeclareUTFCompositeSymbol\textsubscript{h}{"2095}
\DeclareUTFCompositeSymbol\textsubscript{k}{"2096}
\DeclareUTFCompositeSymbol\textsubscript{l}{"2097}
\DeclareUTFCompositeSymbol\textsubscript{m}{"2098}
\DeclareUTFCompositeSymbol\textsubscript{n}{"2099}
\DeclareUTFCompositeSymbol\textsubscript{p}{"209A}
\DeclareUTFCompositeSymbol\textsubscript{s}{"209B}
\DeclareUTFCompositeSymbol\textsubscript{t}{"209C}
%    \end{macrocode}
%
% \changes{v3.2.9}{2013/12/07}
% {增加 \file{xunicode-extra.def} 中，用于加入 \file{puenc.def} 中的符号定义。}
%
% 以下定义取自 \pkg{hyperref} 的 \file{puenc.def}。
%    \begin{macrocode}
\DeclareUTFEncodedAccent\textinvbreve{"0311}{"0311}
\DeclareUTFEncodedSymbol\textsubbreve{"032E}{"203F}
\DeclareUTFSymbol\textHT{"0009}
\DeclareUTFSymbol\textLF{"000A}
\DeclareUTFSymbol\textCR{"000D}
\DeclareUTFSymbol\textnumbersign{"0023}
\DeclareUTFSymbol\textparenleft{"0028}
\DeclareUTFSymbol\textparenright{"0029}
\DeclareUTFSymbol\textMVPlus{"002B}
\DeclareUTFSymbol\textMVComma{"002C}
\DeclareUTFSymbol\textMVMinus{"002D}
\DeclareUTFSymbol\textMVPeriod{"002E}
\DeclareUTFSymbol\textMVDivision{"002F}
\DeclareUTFSymbol\textMVZero{"0030}
\DeclareUTFSymbol\textMVOne{"0031}
\DeclareUTFSymbol\textMVTwo{"0032}
\DeclareUTFSymbol\textMVThree{"0033}
\DeclareUTFSymbol\textMVFour{"0034}
\DeclareUTFSymbol\textMVFive{"0035}
\DeclareUTFSymbol\textMVSix{"0036}
\DeclareUTFSymbol\textMVSeven{"0037}
\DeclareUTFSymbol\textMVEight{"0038}
\DeclareUTFSymbol\textMVNine{"0039}
\DeclareUTFSymbol\textMVAt{"0040}
\DeclareUTFCompositeCommand\.{\i}{i}
\DeclareUTFCompositeCommand\.{i}{i}
\DeclareUTFSymbol\textlnot{"00AC}
\DeclareUTFSymbol\textplusminus{"00B1}
\DeclareUTFSymbol\textcedilla{"00B8}
\DeclareUTFSymbol\textmultiply{"00D7}
\DeclareUTFSymbol\textThorn{"00DE}
\DeclareUTFSymbol\textdivide{"00F7}
\DeclareUTFSymbol\textHslash{"0126}
\DeclareUTFCompositeSymbol\k{\i}{"012F}
\DeclareUTFCompositeSymbol\.{L}{"013F}
\DeclareUTFCompositeSymbol\.{l}{"0140}
\DeclareUTFSymbol\textnapostrophe{"0149}
\DeclareUTFSymbol\textTslash{"0166}
\DeclareUTFSymbol\texttslash{"0167}
\DeclareUTFSymbol\textlongs{"017F}
\DeclareUTFSymbol\texthausaB{"0181}
\DeclareUTFSymbol\texthausaD{"018A}
\DeclareUTFSymbol\textrevE{"018E}
\DeclareUTFSymbol\texthausaK{"0198}
\DeclareUTFSymbol\textPUnrleg{"019E}
\DeclareUTFSymbol\textinve{"01DD}
\DeclareUTFSymbol\textGslash{"01E4}
\DeclareUTFSymbol\textgslash{"01E5}
\DeclareUTFCompositeSymbol\textinvbreve{E}{"0206}
\DeclareUTFCompositeSymbol\textinvbreve{e}{"0207}
\DeclareUTFCompositeSymbol\textinvbreve{I}{"020A}
\DeclareUTFCompositeSymbol\textinvbreve{i}{"020B}
\DeclareUTFCompositeSymbol\textinvbreve{\i}{"020B}
\DeclareUTFCompositeSymbol\textinvbreve{O}{"020E}
\DeclareUTFCompositeSymbol\textinvbreve{o}{"020F}
\DeclareUTFCompositeSymbol\textinvbreve{U}{"0216}
\DeclareUTFCompositeSymbol\textinvbreve{u}{"0217}
\DeclareUTFSymbol\j{"0237}
\DeclareUTFSymbol\textPUdblig{"0238}
\DeclareUTFSymbol\textPUqplig{"0239}
\DeclareUTFSymbol\textslashc{"023C}
\DeclareUTFSymbol\textniepsilon{"025B}
\DeclareUTFSymbol\textipagamma{"0263}
\DeclareUTFSymbol\textniiota{"0269}
\DeclareUTFSymbol\textniphi{"0278}
\DeclareUTFSymbol\textniupsilon{"028A}
\DeclareUTFSymbol\textring{"02DA}
\DeclareUTFSymbol\texttilde{"02DC}
\DeclareUTFSymbol\texthungarumlaut{"02DD}
\DeclareUTFSymbol\textringlow{"02F3}
\DeclareUTFSymbol\texttildelow{"02F7}
\DeclareUTFCommand\textnewtie{\textinvbreve\ }
\DeclareUTFCommand\textdotbelow{\d\ }
\DeclareUTFSymbol\textmacronbelow{"02CD}
\DeclareUTFCommand\texttie{\t\ }
\DeclareUTFSymbol\textnumeralsigngreek{"0374}
\DeclareUTFSymbol\textnumeralsignlowergreek{"0375}
\DeclareUTFCompositeSymbol\'{\textAlpha}{"0386}
\DeclareUTFCompositeSymbol\'{\textEpsilon}{"0388}
\DeclareUTFCompositeSymbol\'{\textEta}{"0389}
\DeclareUTFCompositeSymbol\'{\textIota}{"038A}
\DeclareUTFCompositeSymbol\'{\textOmicron}{"038C}
\DeclareUTFCompositeSymbol\'{\textUpsilon}{"038E}
\DeclareUTFCompositeSymbol\'{\textOmega}{"038F}
\DeclareUTFCompositeSymbol\'{\textIotadieresis}{"0390}
\DeclareUTFSymbol\textIotadieresis{"03AA}
\DeclareUTFCompositeSymbol\"{\textIota}{"03AA}
\DeclareUTFCompositeSymbol\"{\textUpsilon}{"03AB}
\DeclareUTFCompositeSymbol\'{\textalpha}{"03AC}
\DeclareUTFCompositeSymbol\'{\textepsilon}{"03AD}
\DeclareUTFCompositeSymbol\'{\texteta}{"03AE}
\DeclareUTFCompositeSymbol\'{\textiota}{"03AF}
\DeclareUTFCompositeSymbol\"{\textupsilonacute}{"03B0}
\DeclareUTFSymbol\textmugreek{"03BC}
\DeclareUTFSymbol\textvarsigma{"03C2}
\DeclareUTFCompositeSymbol\"{\textiota}{"03CA}
\DeclareUTFCompositeSymbol\"{\textupsilon}{"03CB}
\DeclareUTFCompositeSymbol\'{\textomicron}{"03CC}
\DeclareUTFSymbol\textupsilonacute{"03CD}
\DeclareUTFCompositeSymbol\'{\textupsilon}{"03CD}
\DeclareUTFCompositeSymbol\'{\textomega}{"03CE}
\DeclareUTFSymbol\textStigmagreek{"03DA}
\DeclareUTFSymbol\textstigmagreek{"03DB}
\DeclareUTFSymbol\textDigammagreek{"03DC}
\DeclareUTFSymbol\textdigammagreek{"03DD}
\DeclareUTFSymbol\textKoppagreek{"03DE}
\DeclareUTFSymbol\textkoppagreek{"03DF}
\DeclareUTFSymbol\textSampigreek{"03E0}
\DeclareUTFSymbol\textsampigreek{"03E1}
\DeclareUTFSymbol\textbackepsilon{"03F6}
\DeclareUTFCompositeSymbol\`{\CYRE}{"0400}
\DeclareUTFSymbol\CYRYO{"0401}
\DeclareUTFCompositeSymbol\"{\CYRE}{"0401}
\DeclareUTFSymbol\CYRDJE{"0402}
\DeclareUTFCompositeSymbol\'{\CYRG}{"0403}
\DeclareUTFSymbol\CYRIE{"0404}
\DeclareUTFSymbol\CYRDZE{"0405}
\DeclareUTFSymbol\CYRII{"0406}
\DeclareUTFSymbol\CYRYI{"0407}
\DeclareUTFCompositeSymbol\"{\CYRII}{"0407}
\DeclareUTFSymbol\CYRJE{"0408}
\DeclareUTFSymbol\CYRLJE{"0409}
\DeclareUTFSymbol\CYRNJE{"040A}
\DeclareUTFSymbol\CYRTSHE{"040B}
\DeclareUTFCompositeSymbol\'{\CYRK}{"040C}
\DeclareUTFCompositeSymbol\`{\CYRI}{"040D}
\DeclareUTFSymbol\CYRUSHRT{"040E}
\DeclareUTFCompositeSymbol\U{\CYRU}{"040E}
\DeclareUTFSymbol\CYRDZHE{"040F}
\DeclareUTFSymbol\CYRA{"0410}
\DeclareUTFSymbol\CYRB{"0411}
\DeclareUTFSymbol\CYRV{"0412}
\DeclareUTFSymbol\CYRG{"0413}
\DeclareUTFSymbol\CYRD{"0414}
\DeclareUTFSymbol\CYRE{"0415}
\DeclareUTFSymbol\CYRZH{"0416}
\DeclareUTFSymbol\CYRZ{"0417}
\DeclareUTFSymbol\CYRI{"0418}
\DeclareUTFSymbol\CYRISHRT{"0419}
\DeclareUTFCompositeSymbol\U{\CYRI}{"0419}
\DeclareUTFSymbol\CYRK{"041A}
\DeclareUTFSymbol\CYRL{"041B}
\DeclareUTFSymbol\CYRM{"041C}
\DeclareUTFSymbol\CYRN{"041D}
\DeclareUTFSymbol\CYRO{"041E}
\DeclareUTFSymbol\CYRP{"041F}
\DeclareUTFSymbol\CYRR{"0420}
\DeclareUTFSymbol\CYRS{"0421}
\DeclareUTFSymbol\CYRT{"0422}
\DeclareUTFSymbol\CYRU{"0423}
\DeclareUTFSymbol\CYRF{"0424}
\DeclareUTFSymbol\CYRH{"0425}
\DeclareUTFSymbol\CYRC{"0426}
\DeclareUTFSymbol\CYRCH{"0427}
\DeclareUTFSymbol\CYRSH{"0428}
\DeclareUTFSymbol\CYRSHCH{"0429}
\DeclareUTFSymbol\CYRHRDSN{"042A}
\DeclareUTFSymbol\CYRERY{"042B}
\DeclareUTFSymbol\CYRSFTSN{"042C}
\DeclareUTFSymbol\CYREREV{"042D}
\DeclareUTFSymbol\CYRYU{"042E}
\DeclareUTFSymbol\CYRYA{"042F}
\DeclareUTFSymbol\cyra{"0430}
\DeclareUTFSymbol\cyrb{"0431}
\DeclareUTFSymbol\cyrv{"0432}
\DeclareUTFSymbol\cyrg{"0433}
\DeclareUTFSymbol\cyrd{"0434}
\DeclareUTFSymbol\cyre{"0435}
\DeclareUTFSymbol\cyrzh{"0436}
\DeclareUTFSymbol\cyrz{"0437}
\DeclareUTFSymbol\cyri{"0438}
\DeclareUTFSymbol\cyrishrt{"0439}
\DeclareUTFCompositeSymbol\U{\cyri}{"0439}
\DeclareUTFSymbol\cyrk{"043A}
\DeclareUTFSymbol\cyrl{"043B}
\DeclareUTFSymbol\cyrm{"043C}
\DeclareUTFSymbol\cyrn{"043D}
\DeclareUTFSymbol\cyro{"043E}
\DeclareUTFSymbol\cyrp{"043F}
\DeclareUTFSymbol\cyrr{"0440}
\DeclareUTFSymbol\cyrs{"0441}
\DeclareUTFSymbol\cyrt{"0442}
\DeclareUTFSymbol\cyru{"0443}
\DeclareUTFSymbol\cyrf{"0444}
\DeclareUTFSymbol\cyrh{"0445}
\DeclareUTFSymbol\cyrc{"0446}
\DeclareUTFSymbol\cyrch{"0447}
\DeclareUTFSymbol\cyrsh{"0448}
\DeclareUTFSymbol\cyrshch{"0449}
\DeclareUTFSymbol\cyrhrdsn{"044A}
\DeclareUTFSymbol\cyrery{"044B}
\DeclareUTFSymbol\cyrsftsn{"044C}
\DeclareUTFSymbol\cyrerev{"044D}
\DeclareUTFSymbol\cyryu{"044E}
\DeclareUTFSymbol\cyrya{"044F}
\DeclareUTFCompositeSymbol\`{\cyre}{"0450}
\DeclareUTFSymbol\cyryo{"0451}
\DeclareUTFCompositeSymbol\"{\cyre}{"0451}
\DeclareUTFSymbol\cyrdje{"0452}
\DeclareUTFCompositeSymbol\'{\cyrg}{"0453}
\DeclareUTFSymbol\cyrie{"0454}
\DeclareUTFSymbol\cyrdze{"0455}
\DeclareUTFSymbol\cyrii{"0456}
\DeclareUTFSymbol\cyryi{"0457}
\DeclareUTFCompositeSymbol\"{\cyrii}{"0457}
\DeclareUTFSymbol\cyrje{"0458}
\DeclareUTFSymbol\cyrlje{"0459}
\DeclareUTFSymbol\cyrnje{"045A}
\DeclareUTFSymbol\cyrtshe{"045B}
\DeclareUTFCompositeSymbol\'{\cyrk}{"045C}
\DeclareUTFCompositeSymbol\`{\cyri}{"045D}
\DeclareUTFSymbol\cyrushrt{"045E}
\DeclareUTFCompositeSymbol\U{\curu}{"045E}
\DeclareUTFSymbol\cyrdzhe{"045F}
\DeclareUTFSymbol\CYROMEGA{"0460}
\DeclareUTFSymbol\cyromega{"0461}
\DeclareUTFSymbol\CYRYAT{"0462}
\DeclareUTFSymbol\cyryat{"0463}
\DeclareUTFSymbol\CYRIOTE{"0464}
\DeclareUTFSymbol\cyriote{"0465}
\DeclareUTFSymbol\CYRLYUS{"0466}
\DeclareUTFSymbol\cyrlyus{"0467}
\DeclareUTFSymbol\CYRIOTLYUS{"0468}
\DeclareUTFSymbol\cyriotlyus{"0469}
\DeclareUTFSymbol\CYRBYUS{"046A}
\DeclareUTFSymbol\cyrbyus{"046B}
\DeclareUTFSymbol\CYRIOTBYUS{"046C}
\DeclareUTFSymbol\cyriotbyus{"046D}
\DeclareUTFSymbol\CYRKSI{"046E}
\DeclareUTFSymbol\cyrksi{"046F}
\DeclareUTFSymbol\CYRPSI{"0470}
\DeclareUTFSymbol\cyrpsi{"0471}
\DeclareUTFSymbol\CYRFITA{"0472}
\DeclareUTFSymbol\cyrfita{"0473}
\DeclareUTFSymbol\CYRIZH{"0474}
\DeclareUTFSymbol\cyrizh{"0475}
\DeclareUTFCompositeSymbol\C{\CYRIZH}{"0476}
\DeclareUTFCompositeSymbol\C{\cyrizh}{"0477}
\DeclareUTFSymbol\CYRUK{"0478}
\DeclareUTFSymbol\cyruk{"0479}
\DeclareUTFSymbol\CYROMEGARND{"047A}
\DeclareUTFSymbol\cyromegarnd{"047B}
\DeclareUTFSymbol\CYROMEGATITLO{"047C}
\DeclareUTFSymbol\cyromegatitlo{"047D}
\DeclareUTFSymbol\CYROT{"047E}
\DeclareUTFSymbol\cyrot{"047F}
\DeclareUTFSymbol\CYRKOPPA{"0480}
\DeclareUTFSymbol\cyrkoppa{"0481}
\DeclareUTFSymbol\cyrthousands{"0482}
\DeclareUTFSymbol\CYRISHRTDSC{"048A}
\DeclareUTFSymbol\cyrishrtdsc{"048B}
\DeclareUTFSymbol\CYRSEMISFTSN{"048C}
\DeclareUTFSymbol\cyrsemisftsn{"048D}
\DeclareUTFSymbol\CYRRTICK{"048E}
\DeclareUTFSymbol\cyrrtick{"048F}
\DeclareUTFSymbol\CYRGUP{"0490}
\DeclareUTFSymbol\cyrgup{"0491}
\DeclareUTFSymbol\CYRGHCRS{"0492}
\DeclareUTFSymbol\cyrghcrs{"0493}
\DeclareUTFSymbol\CYRGHK{"0494}
\DeclareUTFSymbol\cyrghk{"0495}
\DeclareUTFSymbol\CYRZHDSC{"0496}
\DeclareUTFSymbol\cyrzhdsc{"0497}
\DeclareUTFSymbol\CYRZDSC{"0498}
\DeclareUTFCompositeSymbol\c{\CYRZ}{"0498}
\DeclareUTFSymbol\cyrzdsc{"0499}
\DeclareUTFCompositeSymbol\c{\cyrz}{"0499}
\DeclareUTFSymbol\CYRKDSC{"049A}
\DeclareUTFSymbol\cyrkdsc{"049B}
\DeclareUTFSymbol\CYRKVCRS{"049C}
\DeclareUTFSymbol\cyrkvcrs{"049D}
\DeclareUTFSymbol\CYRKHCRS{"049E}
\DeclareUTFSymbol\cyrkhcrs{"049F}
\DeclareUTFSymbol\CYRKBEAK{"04A0}
\DeclareUTFSymbol\cyrkbeak{"04A1}
\DeclareUTFSymbol\CYRNDSC{"04A2}
\DeclareUTFSymbol\cyrndsc{"04A3}
\DeclareUTFSymbol\CYRNG{"04A4}
\DeclareUTFSymbol\cyrng{"04A5}
\DeclareUTFSymbol\CYRPHK{"04A6}
\DeclareUTFSymbol\cyrphk{"04A7}
\DeclareUTFSymbol\CYRABHHA{"04A8}
\DeclareUTFSymbol\cyrabhha{"04A9}
\DeclareUTFSymbol\CYRSDSC{"04AA}
\DeclareUTFCompositeSymbol\CYRSDSC{\CYRS}{"04AA}
\DeclareUTFSymbol\cyrsdsc{"04AB}
\DeclareUTFCompositeSymbol\k{\cyrs}{"04AB}
\DeclareUTFSymbol\CYRTDSC{"04AC}
\DeclareUTFSymbol\cyrtdsc{"04AD}
\DeclareUTFSymbol\CYRY{"04AE}
\DeclareUTFSymbol\cyry{"04AF}
\DeclareUTFSymbol\CYRYHCRS{"04B0}
\DeclareUTFSymbol\cyryhcrs{"04B1}
\DeclareUTFSymbol\CYRHDSC{"04B2}
\DeclareUTFSymbol\cyrhdsc{"04B3}
\DeclareUTFSymbol\CYRTETSE{"04B4}
\DeclareUTFSymbol\cyrtetse{"04B5}
\DeclareUTFSymbol\CYRCHRDSC{"04B6}
\DeclareUTFSymbol\cyrchrdsc{"04B7}
\DeclareUTFSymbol\CYRCHVCRS{"04B8}
\DeclareUTFSymbol\cyrchvcrs{"04B9}
\DeclareUTFSymbol\CYRSHHA{"04BA}
\DeclareUTFSymbol\cyrshha{"04BB}
\DeclareUTFSymbol\CYRABHCH{"04BC}
\DeclareUTFSymbol\cyrabhch{"04BD}
\DeclareUTFSymbol\CYRABHCHDSC{"04BE}
\DeclareUTFCompositeSymbol\k{\CYRABHCH}{"04BE}
\DeclareUTFSymbol\cyrabhchdsc{"04BF}
\DeclareUTFCompositeSymbol\k{\cyrabhch}{"04BF}
\DeclareUTFSymbol\CYRpalochka{"04C0}
\DeclareUTFCompositeSymbol\U{\CYRZH}{"04C1}
\DeclareUTFCompositeSymbol\U{\cyrzh}{"04C2}
\DeclareUTFSymbol\CYRKHK{"04C3}
\DeclareUTFSymbol\cyrkhk{"04C4}
\DeclareUTFSymbol\CYRLDSC{"04C5}
\DeclareUTFSymbol\cyrldsc{"04C6}
\DeclareUTFSymbol\CYRNHK{"04C7}
\DeclareUTFSymbol\cyrnhk{"04C8}
\DeclareUTFSymbol\CYRCHLDSC{"04CB}
\DeclareUTFSymbol\cyrchldsc{"04CC}
\DeclareUTFSymbol\CYRMDSC{"04CD}
\DeclareUTFSymbol\cyrmdsc{"04CE}
\DeclareUTFCompositeSymbol\U{\CYRA}{"04D0}
\DeclareUTFCompositeSymbol\U{\cyra}{"04D1}
\DeclareUTFCompositeSymbol\"{\CYRA}{"04D2}
\DeclareUTFCompositeSymbol\"{\cyra}{"04D3}
\DeclareUTFSymbol\CYRAE{"04D4}
\DeclareUTFSymbol\cyrae{"04D5}
\DeclareUTFCompositeSymbol\U{\CYRE}{"04D6}
\DeclareUTFCompositeSymbol\U{\cyre}{"04D7}
\DeclareUTFSymbol\CYRSCHWA{"04D8}
\DeclareUTFSymbol\cyrschwa{"04D9}
\DeclareUTFCompositeSymbol\"{\CYRSCHWA}{"04DA}
\DeclareUTFCompositeSymbol\"{\cyrschwa}{"04DB}
\DeclareUTFCompositeSymbol\"{\CYRZH}{"04DC}
\DeclareUTFCompositeSymbol\"{\cyrzh}{"04DD}
\DeclareUTFCompositeSymbol\"{\CYRZ}{"04DE}
\DeclareUTFCompositeSymbol\"{\cyrz}{"04DF}
\DeclareUTFSymbol\CYRABHDZE{"04E0}
\DeclareUTFSymbol\cyrabhdze{"04E1}
\DeclareUTFCompositeSymbol\={\CYRI}{"04E2}
\DeclareUTFCompositeSymbol\={\cyri}{"04E3}
\DeclareUTFCompositeSymbol\"{\CYRI}{"04E4}
\DeclareUTFCompositeSymbol\"{\cyri}{"04E5}
\DeclareUTFCompositeSymbol\"{\CYRO}{"04E6}
\DeclareUTFCompositeSymbol\"{\cyro}{"04E7}
\DeclareUTFSymbol\CYROTLD{"04E8}
\DeclareUTFSymbol\cyrotld{"04E9}
\DeclareUTFCompositeSymbol\"{\CYROTLD}{"04EA}
\DeclareUTFCompositeSymbol\"{\cyrotld}{"04EB}
\DeclareUTFCompositeSymbol\"{\CYREREV}{"04EC}
\DeclareUTFCompositeSymbol\"{\cyreref}{"04ED}
\DeclareUTFCompositeSymbol\={\CYRU}{"04EE}
\DeclareUTFCompositeSymbol\={\cyru}{"04EF}
\DeclareUTFCompositeSymbol\"{\CYRU}{"04F0}
\DeclareUTFCompositeSymbol\"{\cyru}{"04F1}
\DeclareUTFCompositeSymbol\H{\CYRU}{"04F2}
\DeclareUTFCompositeSymbol\H{\cyru}{"04F3}
\DeclareUTFCompositeSymbol\"{\CYRCH}{"04F4}
\DeclareUTFCompositeSymbol\"{\cyrch}{"04F5}
\DeclareUTFSymbol\CYRGDSC{"04F6}
\DeclareUTFSymbol\cyrgdsc{"04F7}
\DeclareUTFCompositeSymbol\"{\CYRERY}{"04F8}
\DeclareUTFCompositeSymbol\"{\cyrery}{"04F9}
\DeclareUTFSymbol\CYRHHK{"04FC}
\DeclareUTFSymbol\cyrhhk{"04FD}
\DeclareUTFSymbol\sofpasuq{"05C3}
\DeclareUTFSymbol\hebalef{"05D0}
\DeclareUTFSymbol\hebbet{"05D1}
\DeclareUTFSymbol\hebgimel{"05D2}
\DeclareUTFSymbol\hebdalet{"05D3}
\DeclareUTFSymbol\hebhe{"05D4}
\DeclareUTFSymbol\hebvav{"05D5}
\DeclareUTFSymbol\hebzayin{"05D6}
\DeclareUTFSymbol\hebhet{"05D7}
\DeclareUTFSymbol\hebtet{"05D8}
\DeclareUTFSymbol\hebyod{"05D9}
\DeclareUTFSymbol\hebfinalkaf{"05DA}
\DeclareUTFSymbol\hebkaf{"05DB}
\DeclareUTFSymbol\heblamed{"05DC}
\DeclareUTFSymbol\hebfinalmem{"05DD}
\DeclareUTFSymbol\hebmem{"05DE}
\DeclareUTFSymbol\hebfinalnun{"05DF}
\DeclareUTFSymbol\hebnun{"05E0}
\DeclareUTFSymbol\hebsamekh{"05E1}
\DeclareUTFSymbol\hebayin{"05E2}
\DeclareUTFSymbol\hebfinalpe{"05E3}
\DeclareUTFSymbol\hebpe{"05E4}
\DeclareUTFSymbol\hebfinaltsadi{"05E5}
\DeclareUTFSymbol\hebtsadi{"05E6}
\DeclareUTFSymbol\hebqof{"05E7}
\DeclareUTFSymbol\hebresh{"05E8}
\DeclareUTFSymbol\hebshin{"05E9}
\DeclareUTFSymbol\hebtav{"05EA}
\DeclareUTFSymbol\doublevav{"05F0}
\DeclareUTFSymbol\vavyod{"05F1}
\DeclareUTFSymbol\doubleyod{"05F2}
\DeclareUTFSymbol\textscd{"1D05}
\DeclareUTFSymbol\textPUsck{"1D0B}
\DeclareUTFSymbol\textPUscm{"1D0D}
\DeclareUTFSymbol\textPUscp{"1D18}
\DeclareUTFSymbol\textPUrevscr{"1D19}
\DeclareUTFSymbol\textiinferior{"1D62}
\DeclareUTFSymbol\textrinferior{"1D63}
\DeclareUTFSymbol\textuinferior{"1D64}
\DeclareUTFSymbol\textvinferior{"1D65}
\DeclareUTFSymbol\textbetainferior{"1D66}
\DeclareUTFSymbol\textgammainferior{"1D67}
\DeclareUTFSymbol\textrhoinferior{"1D68}
\DeclareUTFSymbol\textphiinferior{"1D69}
\DeclareUTFSymbol\textchiinferior{"1D6A}
\DeclareUTFSymbol\textbarsci{"1D7B}
\DeclareUTFSymbol\textbarp{"1D7D}
\DeclareUTFSymbol\textbarscu{"1D7E}
\DeclareUTFSymbol\textPUrhooka{"1D8F}
\DeclareUTFSymbol\textPUrhooke{"1D92}
\DeclareUTFSymbol\textPUrhookepsilon{"1D93}
\DeclareUTFSymbol\textPUrhookopeno{"1D97}
\DeclareUTFCompositeSymbol\textsubbreve{H}{"1E2A}
\DeclareUTFCompositeSymbol\textsubbreve{h}{"1E2B}
\DeclareUTFCompositeSymbol\.{\textlongs}{"1E9B}
\DeclareUTFSymbol\textcompwordmark{"200C}
\DeclareUTFSymbol\texthdotfor{"2025}
\DeclareUTFSymbol\textprime{"2032}
\DeclareUTFSymbol\textsecond{"2033}
\DeclareUTFSymbol\textthird{"2034}
\DeclareUTFSymbol\textbackprime{"2035}
\DeclareUTFSymbol\textlefttherefore{"2056}
\DeclareUTFSymbol\textfourth{"2057}
\DeclareUTFSymbol\textdiamonddots{"2058}
\DeclareUTFSymbol\textzerosuperior{"2070}
\DeclareUTFSymbol\textisuperior{"2071}
\DeclareUTFSymbol\textfoursuperior{"2074}
\DeclareUTFSymbol\textfivesuperior{"2075}
\DeclareUTFSymbol\textsixsuperior{"2076}
\DeclareUTFSymbol\textsevensuperior{"2077}
\DeclareUTFSymbol\texteightsuperior{"2078}
\DeclareUTFSymbol\textninesuperior{"2079}
\DeclareUTFSymbol\textplussuperior{"207A}
\DeclareUTFSymbol\textminussuperior{"207B}
\DeclareUTFSymbol\textequalsuperior{"207C}
\DeclareUTFSymbol\textparenleftsuperior{"207D}
\DeclareUTFSymbol\textparenrightsuperior{"207E}
\DeclareUTFSymbol\textnsuperior{"207F}
\DeclareUTFSymbol\textzeroinferior{"2080}
\DeclareUTFSymbol\textoneinferior{"2081}
\DeclareUTFSymbol\texttwoinferior{"2082}
\DeclareUTFSymbol\textthreeinferior{"2083}
\DeclareUTFSymbol\textfourinferior{"2084}
\DeclareUTFSymbol\textfiveinferior{"2085}
\DeclareUTFSymbol\textsixinferior{"2086}
\DeclareUTFSymbol\textseveninferior{"2087}
\DeclareUTFSymbol\texteightinferior{"2088}
\DeclareUTFSymbol\textnineinferior{"2089}
\DeclareUTFSymbol\textplusinferior{"208A}
\DeclareUTFSymbol\textminusinferior{"208B}
\DeclareUTFSymbol\textequalsinferior{"208C}
\DeclareUTFSymbol\textparenleftinferior{"208D}
\DeclareUTFSymbol\textparenrightinferior{"208E}
\DeclareUTFSymbol\textainferior{"2090}
\DeclareUTFSymbol\texteinferior{"2091}
\DeclareUTFSymbol\textoinferior{"2092}
\DeclareUTFSymbol\textxinferior{"2093}
\DeclareUTFSymbol\textschwainferior{"2094}
\DeclareUTFSymbol\texthinferior{"2095}
\DeclareUTFSymbol\textkinferior{"2096}
\DeclareUTFSymbol\textlinferior{"2097}
\DeclareUTFSymbol\textminferior{"2098}
\DeclareUTFSymbol\textninferior{"2099}
\DeclareUTFSymbol\textpinferior{"209A}
\DeclareUTFSymbol\textsinferior{"209B}
\DeclareUTFSymbol\texttinferior{"209C}
\DeclareUTFSymbol\textpeseta{"20A7}
\DeclareUTFSymbol\textDeleatur{"20B0}
\DeclareUTFSymbol\textguarani{"20B2}
\DeclareUTFSymbol\texthslash{"210F}
\DeclareUTFSymbol\textIm{"2111}
\DeclareUTFSymbol\textell{"2113}
\DeclareUTFSymbol\textwp{"2118}
\DeclareUTFSymbol\textRe{"211C}
\DeclareUTFSymbol\textriota{"2129}
\DeclareUTFSymbol\textangstrom{"212B}
\DeclareUTFSymbol\textfax{"213B}
\DeclareUTFSymbol\textinvamp{"214B}
\DeclareUTFSymbol\textoneseventh{"2150}
\DeclareUTFSymbol\textoneninth{"2151}
\DeclareUTFSymbol\textonetenth{"2152}
\DeclareUTFSymbol\textonethird{"2153}
\DeclareUTFSymbol\texttwothirds{"2154}
\DeclareUTFSymbol\textonefifth{"2155}
\DeclareUTFSymbol\texttwofifths{"2156}
\DeclareUTFSymbol\textthreefifths{"2157}
\DeclareUTFSymbol\textfourfifths{"2158}
\DeclareUTFSymbol\textonesixth{"2159}
\DeclareUTFSymbol\textfivesixths{"215A}
\DeclareUTFSymbol\textoneeighth{"215B}
\DeclareUTFSymbol\textthreeeighths{"215C}
\DeclareUTFSymbol\textfiveeighths{"215D}
\DeclareUTFSymbol\textseveneighths{"215E}
\DeclareUTFSymbol\textrevc{"2184}
\DeclareUTFSymbol\textzerothirds{"2189}
\DeclareUTFSymbol\textnleftarrow{"219A}
\DeclareUTFSymbol\textnrightarrow{"219B}
\DeclareUTFSymbol\texttwoheadleftarrow{"219E}
\DeclareUTFCommand\textntwoheadleftarrow{\textlstrikethru\texttwoheadleftarrow}
\DeclareUTFSymbol\texttwoheaduparrow{"219F}
\DeclareUTFSymbol\texttwoheadrightarrow{"21A0}
\DeclareUTFCommand\textntwoheadrightarrow{\textlstrikethru\texttwoheadrightarrow}
\DeclareUTFSymbol\texttwoheaddownarrow{"21A1}
\DeclareUTFSymbol\textleftarrowtail{"21A2}
\DeclareUTFSymbol\textrightarrowtail{"21A3}
\DeclareUTFSymbol\textmapsto{"21A6}
\DeclareUTFSymbol\texthookleftarrow{"21A9}
\DeclareUTFSymbol\texthookrightarrow{"21AA}
\DeclareUTFSymbol\textlooparrowleft{"21AB}
\DeclareUTFSymbol\textlooparrowright{"21AC}
\DeclareUTFSymbol\textnleftrightarrow{"21AE}
\DeclareUTFSymbol\textlightning{"21AF}
\DeclareUTFSymbol\textdlsh{"21B5}
\DeclareUTFSymbol\textcurvearrowleft{"21B6}
\DeclareUTFSymbol\textcurvearrowright{"21B7}
\DeclareUTFSymbol\textleftharpoonup{"21BC}
\DeclareUTFSymbol\textleftharpoondown{"21BD}
\DeclareUTFSymbol\textupharpoonright{"21BE}
\DeclareUTFSymbol\textupharpoonleft{"21BF}
\DeclareUTFSymbol\textrightharpoonup{"21C0}
\DeclareUTFSymbol\textrightharpoondown{"21C1}
\DeclareUTFSymbol\textdownharpoonright{"21C2}
\DeclareUTFSymbol\textdownharpoonleft{"21C3}
\DeclareUTFSymbol\textrightleftarrows{"21C4}
\DeclareUTFSymbol\textupdownarrows{"21C5}
\DeclareUTFSymbol\textleftrightarrows{"21C6}
\DeclareUTFSymbol\textleftleftarrows{"21C7}
\DeclareUTFSymbol\textupuparrows{"21C8}
\DeclareUTFSymbol\textrightrightarrows{"21C9}
\DeclareUTFSymbol\textdowndownarrows{"21CA}
\DeclareUTFSymbol\textleftrightharpoons{"21CB}
\DeclareUTFSymbol\textrightleftharpoons{"21CC}
\DeclareUTFSymbol\textnLeftarrow{"21CD}
\DeclareUTFSymbol\textnLeftrightarrow{"21CE}
\DeclareUTFSymbol\textnRightarrow{"21CF}
\DeclareUTFSymbol\textLeftarrow{"21D0}
\DeclareUTFSymbol\textUparrow{"21D1}
\DeclareUTFSymbol\textRightarrow{"21D2}
\DeclareUTFSymbol\textDownarrow{"21D3}
\DeclareUTFSymbol\textLeftrightarrow{"21D4}
\DeclareUTFSymbol\textUpdownarrow{"21D5}
\DeclareUTFSymbol\textNwarrow{"21D6}
\DeclareUTFSymbol\textNearrow{"21D7}
\DeclareUTFSymbol\textSearrow{"21D8}
\DeclareUTFSymbol\textSwarrow{"21D9}
\DeclareUTFSymbol\textLleftarrow{"21DA}
\DeclareUTFSymbol\textRrightarrow{"21DB}
\DeclareUTFSymbol\textleftsquigarrow{"21DC}
\DeclareUTFSymbol\textrightsquigarrow{"21DD}
\DeclareUTFSymbol\textdashleftarrow{"21E0}
\DeclareUTFSymbol\textdasheduparrow{"21E1}
\DeclareUTFSymbol\textdashrightarrow{"21E2}
\DeclareUTFSymbol\textdasheddownarrow{"21E3}
\DeclareUTFSymbol\textpointer{"21E8}
\DeclareUTFSymbol\textdownuparrows{"21F5}
\DeclareUTFSymbol\textleftarrowtriangle{"21FD}
\DeclareUTFSymbol\textrightarrowtriangle{"21FE}
\DeclareUTFSymbol\textleftrightarrowtriangle{"21FF}
\DeclareUTFSymbol\textforall{"2200}
\DeclareUTFSymbol\textcomplement{"2201}
\DeclareUTFSymbol\textpartial{"2202}
\DeclareUTFSymbol\textexists{"2203}
\DeclareUTFSymbol\textnexists{"2204}
\DeclareUTFSymbol\textemptyset{"2205}
\DeclareUTFSymbol\texttriangle{"2206}
\DeclareUTFSymbol\textnabla{"2207}
\DeclareUTFSymbol\textin{"2208}
\DeclareUTFSymbol\textnotin{"2209}
\DeclareUTFSymbol\textsmallin{"220A}
\DeclareUTFSymbol\textni{"220B}
\DeclareUTFSymbol\textnotowner{"220C}
\DeclareUTFSymbol\textsmallowns{"220D}
\DeclareUTFSymbol\textprod{"220F}
\DeclareUTFSymbol\textamalg{"2210}
\DeclareUTFSymbol\textsum{"2211}
\DeclareUTFSymbol\textmp{"2213}
\DeclareUTFSymbol\textdotplus{"2214}
\DeclareUTFSymbol\textDivides{"2215}
\DeclareUTFSymbol\textsetminus{"2216}
\DeclareUTFSymbol\textast{"2217}
\DeclareUTFSymbol\textcirc{"2218}
\DeclareUTFSymbol\textbulletoperator{"2219}
\DeclareUTFSymbol\textpropto{"221D}
\DeclareUTFSymbol\textinfty{"221E}
\DeclareUTFSymbol\textangle{"2220}
\DeclareUTFSymbol\textmeasuredangle{"2221}
\DeclareUTFSymbol\textsphericalangle{"2222}
\DeclareUTFSymbol\textmid{"2223}
\DeclareUTFSymbol\textnmid{"2224}
\DeclareUTFSymbol\textparallel{"2225}
\DeclareUTFSymbol\textnparallel{"2226}
\DeclareUTFSymbol\textwedge{"2227}
\DeclareUTFCommand\textowedge{\textcircled\textwedge}
\DeclareUTFSymbol\textvee{"2228}
\DeclareUTFCommand\textovee{\textcircled\textvee}
\DeclareUTFSymbol\textcap{"2229}
\DeclareUTFSymbol\textcup{"222A}
\DeclareUTFSymbol\textint{"222B}
\DeclareUTFSymbol\textiint{"222C}
\DeclareUTFSymbol\textiiint{"222D}
\DeclareUTFSymbol\textoint{"222E}
\DeclareUTFSymbol\textoiint{"222F}
\DeclareUTFSymbol\textointclockwise{"2232}
\DeclareUTFSymbol\textointctrclockwise{"2233}
\DeclareUTFSymbol\texttherefore{"2234}
\DeclareUTFSymbol\textbecause{"2235}
\DeclareUTFSymbol\textvdotdot{"2236}
\DeclareUTFSymbol\textsquaredots{"2237}
\DeclareUTFSymbol\textdotminus{"2238}
\DeclareUTFSymbol\texteqcolon{"2239}
\DeclareUTFSymbol\textsim{"223C}
\DeclareUTFSymbol\textbacksim{"223D}
\DeclareUTFCommand\textnbacksim{\textlstrikethru\textnbacksim}
\DeclareUTFSymbol\textwr{"2240}
\DeclareUTFSymbol\textnsim{"2241}
\DeclareUTFSymbol\texteqsim{"2242}
\DeclareUTFCommand\textneqsim{\textlstrikethru\texteqsim}
\DeclareUTFSymbol\textsimeq{"2243}
\DeclareUTFSymbol\textnsimeq{"2244}
\DeclareUTFSymbol\textcong{"2245}
\DeclareUTFSymbol\textncong{"2247}
\DeclareUTFSymbol\textapprox{"2248}
\DeclareUTFSymbol\textnapprox{"2249}
\DeclareUTFSymbol\textapproxeq{"224A}
\DeclareUTFCommand\textnapproxeq{\textlstrikethru\textapproxeq}
\DeclareUTFSymbol\texttriplesim{"224B}
\DeclareUTFCommand\textntriplesim{\textlstrikethru\texttriplesim}
\DeclareUTFSymbol\textbackcong{"224C}
\DeclareUTFCommand\textnbackcong{\textlstrikethru\textbackcong}
\DeclareUTFSymbol\textasymp{"224D}
\DeclareUTFCommand\textnasymp{\textlstrikethru\textasymp}
\DeclareUTFSymbol\textBumpeq{"224E}
\DeclareUTFCommand\textnBumpeq{\textlstrikethru\textBumpeq}
\DeclareUTFSymbol\textbumpeq{"224F}
\DeclareUTFCommand\textnbumpeq{\textlstrikethru\textbumpeq}
\DeclareUTFSymbol\textdoteq{"2250}
\DeclareUTFCommand\textndoteq{\textlstrikethru\textdoteq}
\DeclareUTFSymbol\textdoteqdot{"2251}
\DeclareUTFCommand\textnDoteq{\textlstrikethru\textdoteqdot}
\DeclareUTFSymbol\textfallingdoteq{"2252}
\DeclareUTFCommand\textnfallingdoteq{\textlstrikethru\textfallingdoteq}
\DeclareUTFSymbol\textrisingdoteq{"2253}
\DeclareUTFCommand\textnrisingdoteq{\textlstrikethru\textrisingdoteq}
\DeclareUTFSymbol\textcolonequals{"2254}
\DeclareUTFSymbol\textequalscolon{"2255}
\DeclareUTFSymbol\texteqcirc{"2256}
\DeclareUTFCommand\textneqcirc{\textlstrikethru\texteqcirc}
\DeclareUTFSymbol\textcirceq{"2257}
\DeclareUTFCommand\textncirceq{\textlstrikethru\textcirceq}
\DeclareUTFSymbol\texthateq{"2259}
\DeclareUTFCommand\textnhateq{\textlstrikethru\texthateq}
\DeclareUTFSymbol\texttriangleeq{"225C}
\DeclareUTFSymbol\textneq{"2260}
\DeclareUTFSymbol\textne{"2260}
\DeclareUTFSymbol\textequiv{"2261}
\DeclareUTFSymbol\textnequiv{"2262}
\DeclareUTFSymbol\textleq{"2264}
\DeclareUTFSymbol\textle{"2264}
\DeclareUTFSymbol\textgeq{"2265}
\DeclareUTFSymbol\textge{"2265}
\DeclareUTFSymbol\textleqq{"2266}
\DeclareUTFCommand\textnleqq{\textlstrikethru\textleqq}
\DeclareUTFSymbol\textgeqq{"2267}
\DeclareUTFCommand\textngeqq{\textlstrikethru\textgeqq}
\DeclareUTFSymbol\textlneqq{"2268}
\DeclareUTFSymbol\textgneqq{"2269}
\DeclareUTFSymbol\textll{"226A}
\DeclareUTFCommand\textnll{\textlstrikethru\textll}
\DeclareUTFSymbol\textgg{"226B}
\DeclareUTFCommand\textngg{\textlstrikethru\textgg}
\DeclareUTFSymbol\textbetween{"226C}
\DeclareUTFSymbol\textnless{"226E}
\DeclareUTFSymbol\textngtr{"226F}
\DeclareUTFSymbol\textnleq{"2270}
\DeclareUTFSymbol\textngeq{"2271}
\DeclareUTFSymbol\textlesssim{"2272}
\DeclareUTFSymbol\textgtrsim{"2273}
\DeclareUTFSymbol\textnlesssim{"2274}
\DeclareUTFSymbol\textngtrsim{"2275}
\DeclareUTFSymbol\textlessgtr{"2276}
\DeclareUTFSymbol\textgtrless{"2277}
\DeclareUTFSymbol\textngtrless{"2278}
\DeclareUTFSymbol\textnlessgtr{"2279}
\DeclareUTFSymbol\textprec{"227A}
\DeclareUTFSymbol\textsucc{"227B}
\DeclareUTFSymbol\textpreccurlyeq{"227C}
\DeclareUTFSymbol\textsucccurlyeq{"227D}
\DeclareUTFSymbol\textprecsim{"227E}
\DeclareUTFCommand\textnprecsim{\textlstrikethru\textprecsim}
\DeclareUTFSymbol\textsuccsim{"227F}
\DeclareUTFCommand\textnsuccsim{\textlstrikethru\textsuccsim}
\DeclareUTFSymbol\textnprec{"2280}
\DeclareUTFSymbol\textnsucc{"2281}
\DeclareUTFSymbol\textsubset{"2282}
\DeclareUTFSymbol\textsupset{"2283}
\DeclareUTFSymbol\textnsubset{"2284}
\DeclareUTFSymbol\textnsupset{"2285}
\DeclareUTFSymbol\textsubseteq{"2286}
\DeclareUTFSymbol\textsupseteq{"2287}
\DeclareUTFSymbol\textnsubseteq{"2288}
\DeclareUTFSymbol\textnsupseteq{"2289}
\DeclareUTFSymbol\textsubsetneq{"228A}
\DeclareUTFSymbol\textsupsetneq{"228B}
\DeclareUTFSymbol\textcupdot{"228D}
\DeclareUTFSymbol\textcupplus{"228E}
\DeclareUTFSymbol\textsqsubset{"228F}
\DeclareUTFCommand\textnsqsubset{\textlstrikethru\textsqsubset}
\DeclareUTFSymbol\textsqsupset{"2290}
\DeclareUTFCommand\textnsqsupset{\textlstrikethru\textsqsupset}
\DeclareUTFSymbol\textsqsubseteq{"2291}
\DeclareUTFCommand\textnsqsubseteq{\textlstrikethru\textsqsubseteq}
\DeclareUTFSymbol\textsqsupseteq{"2292}
\DeclareUTFCommand\textnsqsupseteq{\textlstrikethru\textsqsupseteq}
\DeclareUTFSymbol\textsqcap{"2293}
\DeclareUTFSymbol\textsqcup{"2294}
\DeclareUTFSymbol\textoplus{"2295}
\DeclareUTFSymbol\textominus{"2296}
\DeclareUTFSymbol\textotimes{"2297}
\DeclareUTFSymbol\textoslash{"2298}
\DeclareUTFSymbol\textodot{"2299}
\DeclareUTFSymbol\textcircledcirc{"229A}
\DeclareUTFSymbol\textcircledast{"229B}
\DeclareUTFSymbol\textcircleddash{"229D}
\DeclareUTFSymbol\textboxplus{"229E}
\DeclareUTFSymbol\textboxminus{"229F}
\DeclareUTFSymbol\textboxtimes{"22A0}
\DeclareUTFSymbol\textboxdot{"22A1}
\DeclareUTFSymbol\textvdash{"22A2}
\DeclareUTFSymbol\textdashv{"22A3}
\DeclareUTFCommand\textndashv{\textlstrikethru\textdashv}
\DeclareUTFSymbol\texttop{"22A4}
\DeclareUTFCommand\textndownvdash{\textlstrikethru\texttop}
\DeclareUTFSymbol\textbot{"22A5}
\DeclareUTFCommand\textnupvdash{\textlstrikethru\textbot}
\DeclareUTFSymbol\textvDash{"22A8}
\DeclareUTFSymbol\textVdash{"22A9}
\DeclareUTFSymbol\textVvdash{"22AA}
\DeclareUTFCommand\textnVvash{\textlstrikethru\textVvdash}
\DeclareUTFSymbol\textVDash{"22AB}
\DeclareUTFSymbol\textnvdash{"22AC}
\DeclareUTFSymbol\textnvDash{"22AD}
\DeclareUTFSymbol\textnVdash{"22AE}
\DeclareUTFSymbol\textnVDash{"22AF}
\DeclareUTFSymbol\textlhd{"22B2}
\DeclareUTFSymbol\textrhd{"22B3}
\DeclareUTFSymbol\textunlhd{"22B4}
\DeclareUTFSymbol\textunrhd{"22B5}
\DeclareUTFSymbol\textmultimapdotbothA{"22B6}
\DeclareUTFSymbol\textmultimapdotbothB{"22B7}
\DeclareUTFSymbol\textmultimap{"22B8}
\DeclareUTFSymbol\textveebar{"22BB}
\DeclareUTFSymbol\textbarwedge{"22BC}
\DeclareUTFSymbol\textstar{"22C6}
\DeclareUTFSymbol\textdivideontimes{"22C7}
\DeclareUTFSymbol\textbowtie{"22C8}
\DeclareUTFSymbol\textltimes{"22C9}
\DeclareUTFSymbol\textrtimes{"22CA}
\DeclareUTFSymbol\textleftthreetimes{"22CB}
\DeclareUTFSymbol\textrightthreetimes{"22CC}
\DeclareUTFSymbol\textbacksimeq{"22CD}
\DeclareUTFCommand\textnbacksimeq{\textlstrikethru\textbacksimeq}
\DeclareUTFSymbol\textcurlyvee{"22CE}
\DeclareUTFSymbol\textcurlywedge{"22CF}
\DeclareUTFSymbol\textSubset{"22D0}
\DeclareUTFCommand\textnSubset{\textlstrikethru\textSubset}
\DeclareUTFSymbol\textSupset{"22D1}
\DeclareUTFCommand\textnSupset{\textlstrikethru\textSupset}
\DeclareUTFSymbol\textCap{"22D2}
\DeclareUTFSymbol\textCup{"22D3}
\DeclareUTFSymbol\textpitchfork{"22D4}
\DeclareUTFSymbol\textlessdot{"22D6}
\DeclareUTFSymbol\textgtrdot{"22D7}
\DeclareUTFSymbol\textlll{"22D8}
\DeclareUTFSymbol\textggg{"22D9}
\DeclareUTFSymbol\textlesseqgtr{"22DA}
\DeclareUTFSymbol\textgtreqless{"22DB}
\DeclareUTFSymbol\textcurlyeqprec{"22DE}
\DeclareUTFCommand\textncurlyeqprec{\textlstrikethru\textcurlyeqprec}
\DeclareUTFSymbol\textcurlyeqsucc{"22DF}
\DeclareUTFCommand\textncurlyeqsucc{\textlstrikethru\textcurlyeqsucc}
\DeclareUTFSymbol\textnpreccurlyeq{"22E0}
\DeclareUTFSymbol\textnsucccurlyeq{"22E1}
\DeclareUTFSymbol\textnqsubseteq{"22E2}
\DeclareUTFSymbol\textnqsupseteq{"22E3}
\DeclareUTFSymbol\textsqsubsetneq{"22E4}
\DeclareUTFSymbol\textsqsupsetneq{"22E5}
\DeclareUTFSymbol\textlnsim{"22E6}
\DeclareUTFSymbol\textgnsim{"22E7}
\DeclareUTFSymbol\textprecnsim{"22E8}
\DeclareUTFSymbol\textsuccnsim{"22E9}
\DeclareUTFSymbol\textntriangleleft{"22EA}
\DeclareUTFSymbol\textntriangleright{"22EB}
\DeclareUTFSymbol\textntrianglelefteq{"22EC}
\DeclareUTFSymbol\textntrianglerighteq{"22ED}
\DeclareUTFSymbol\textvdots{"22EE}
\DeclareUTFSymbol\textcdots{"22EF}
\DeclareUTFSymbol\textudots{"22F0}
\DeclareUTFSymbol\textddots{"22F1}
\DeclareUTFSymbol\textbarin{"22F6}
\DeclareUTFSymbol\textdiameter{"2300}
\DeclareUTFSymbol\textbackneg{"2310}
\DeclareUTFSymbol\textwasylozenge{"2311}
\DeclareUTFSymbol\textinvbackneg{"2319}
\DeclareUTFSymbol\textclock{"231A}
\DeclareUTFSymbol\textulcorner{"231C}
\DeclareUTFSymbol\texturcorner{"231D}
\DeclareUTFSymbol\textllcorner{"231E}
\DeclareUTFSymbol\textlrcorner{"231F}
\DeclareUTFSymbol\textfrown{"2322}
\DeclareUTFSymbol\textsmile{"2323}
\DeclareUTFSymbol\textKeyboard{"2328}
\DeclareUTFSymbol\textlangle{"2329}
\DeclareUTFSymbol\textrangle{"232A}
\DeclareUTFSymbol\textAPLinv{"2339}
\DeclareUTFSymbol\textTumbler{"233C}
\DeclareUTFSymbol\textstmaryrdbaro{"233D}
\DeclareUTFSymbol\textnotslash{"233F}
\DeclareUTFSymbol\textnotbackslash{"2340}
\DeclareUTFSymbol\textboxbackslash{"2342}
\DeclareUTFSymbol\textAPLleftarrowbox{"2347}
\DeclareUTFSymbol\textAPLrightarrowbox{"2348}
\DeclareUTFSymbol\textAPLuparrowbox{"2350}
\DeclareUTFSymbol\textAPLdownarrowbox{"2357}
\DeclareUTFSymbol\textAPLinput{"235E}
\DeclareUTFSymbol\textRequest{"2370}
\DeclareUTFSymbol\textBeam{"2393}
\DeclareUTFSymbol\texthexagon{"2394}
\DeclareUTFSymbol\textAPLbox{"2395}
\DeclareUTFSymbol\textForwardToIndex{"23ED}
\DeclareUTFSymbol\textRewindToIndex{"23EE}
\DeclareUTFSymbol\textbbslash{"244A}
\DeclareUTFSymbol\textCircledA{"24B6}
\DeclareUTFSymbol\textCleaningF{"24BB}
\DeclareUTFCommand\textCleaningFF{\b\textCleaningF}
\DeclareUTFSymbol\textCleaningP{"24C5}
\DeclareUTFCommand\textCleaningPP{\b\textCleaningP}
\DeclareUTFSymbol\textCuttingLine{"2504}
\DeclareUTFSymbol\textUParrow{"25B2}
\DeclareUTFSymbol\textbigtriangleup{"25B3}
\DeclareUTFSymbol\textForward{"25B6}
\DeclareUTFSymbol\texttriangleright{"25B7}
\DeclareUTFSymbol\textRHD{"25BA}
\DeclareUTFSymbol\textDOWNarrow{"25BC}
\DeclareUTFSymbol\textbigtriangledown{"25BD}
\DeclareUTFSymbol\textRewind{"25C0}
\DeclareUTFSymbol\texttriangleleft{"25C1}
\DeclareUTFSymbol\textLHD{"25C4}
\DeclareUTFSymbol\textdiamond{"25C7}
\DeclareUTFSymbol\textlozenge{"25CA}
\DeclareUTFSymbol\textLEFTCIRCLE{"25D6}
\DeclareUTFSymbol\textRIGHTCIRCLE{"25D7}
\DeclareUTFSymbol\textboxbar{"25EB}
\DeclareUTFSymbol\textCloud{"2601}
\DeclareUTFSymbol\textFiveStar{"2605}
\DeclareUTFSymbol\textFiveStarOpen{"2606}
\DeclareUTFSymbol\textPhone{"260E}
\DeclareUTFSymbol\textboxempty{"2610}
\DeclareUTFSymbol\textCheckedbox{"2611}
\DeclareUTFSymbol\textCrossedbox{"2612}
\DeclareUTFSymbol\textCoffeecup{"2615}
\DeclareUTFSymbol\textHandCuffLeft{"261A}
\DeclareUTFSymbol\textHandCuffRight{"261B}
\DeclareUTFSymbol\textHandLeft{"261C}
\DeclareUTFSymbol\textHandRight{"261E}
\DeclareUTFSymbol\textRadioactivity{"2622}
\DeclareUTFSymbol\textBiohazard{"2623}
\DeclareUTFSymbol\textAnkh{"2625}
\DeclareUTFSymbol\textYinYang{"262F}
\DeclareUTFSymbol\textfrownie{"2639}
\DeclareUTFSymbol\textsmiley{"263A}
\DeclareUTFSymbol\textblacksmiley{"263B}
\DeclareUTFSymbol\textsun{"263C}
\DeclareUTFSymbol\textleftmoon{"263D}
\DeclareUTFSymbol\textrightmoon{"263E}
\DeclareUTFSymbol\textmercury{"263F}
\DeclareUTFSymbol\textPUfemale{"2640}
\DeclareUTFSymbol\textearth{"2641}
\DeclareUTFSymbol\textmale{"2642}
\DeclareUTFSymbol\textjupiter{"2643}
\DeclareUTFSymbol\textsaturn{"2644}
\DeclareUTFSymbol\texturanus{"2645}
\DeclareUTFSymbol\textneptune{"2646}
\DeclareUTFSymbol\textpluto{"2647}
\DeclareUTFSymbol\textaries{"2648}
\DeclareUTFSymbol\texttaurus{"2649}
\DeclareUTFSymbol\textgemini{"264A}
\DeclareUTFSymbol\textcancer{"264B}
\DeclareUTFSymbol\textleo{"264C}
\DeclareUTFSymbol\textvirgo{"264D}
\DeclareUTFSymbol\textlibra{"264E}
\DeclareUTFSymbol\textscorpio{"264F}
\DeclareUTFSymbol\textsagittarius{"2650}
\DeclareUTFSymbol\textcapricornus{"2651}
\DeclareUTFSymbol\textaquarius{"2652}
\DeclareUTFSymbol\textpisces{"2653}
\DeclareUTFSymbol\textspadesuitblack{"2660}
\DeclareUTFSymbol\textheartsuitwhite{"2661}
\DeclareUTFSymbol\textdiamondsuitwhite{"2662}
\DeclareUTFSymbol\textclubsuitblack{"2663}
\DeclareUTFSymbol\textspadesuitwhite{"2664}
\DeclareUTFSymbol\textheartsuitblack{"2665}
\DeclareUTFSymbol\textdiamondsuitblack{"2666}
\DeclareUTFSymbol\textclubsuitwhite{"2667}
\DeclareUTFSymbol\textquarternote{"2669}
\DeclareUTFSymbol\texttwonotes{"266B}
\DeclareUTFSymbol\textsixteenthnote{"266C}
\DeclareUTFSymbol\textflat{"266D}
\DeclareUTFSymbol\textnatural{"266E}
\DeclareUTFSymbol\textsharp{"266F}
\DeclareUTFSymbol\textrecycle{"2672}
\DeclareUTFSymbol\textWheelchair{"267F}
\DeclareUTFSymbol\textFlag{"2691}
\DeclareUTFSymbol\textMineSign{"2692}
\DeclareUTFSymbol\textdsmilitary{"2694}
\DeclareUTFSymbol\textdsmedical{"2695}
\DeclareUTFSymbol\textdsjuridical{"2696}
\DeclareUTFSymbol\textdschemical{"2697}
\DeclareUTFSymbol\textdsbiological{"2698}
\DeclareUTFSymbol\textdscommercial{"269A}
\DeclareUTFSymbol\textmanstar{"269D}
\DeclareUTFSymbol\textdanger{"26A0}
\DeclareUTFSymbol\textFemaleFemale{"26A2}
\DeclareUTFSymbol\textMaleMale{"26A3}
\DeclareUTFSymbol\textFemaleMale{"26A4}
\DeclareUTFSymbol\textHermaphrodite{"26A5}
\DeclareUTFSymbol\textNeutral{"26AA}
\DeclareUTFSymbol\textPUuncrfemale{"26B2}
\DeclareUTFSymbol\texthexstar{"26B9}
\DeclareUTFSymbol\textSoccerBall{"26BD}
\DeclareUTFSymbol\textSunCload{"26C5}
\DeclareUTFSymbol\textRain{"26C6}
\DeclareUTFSymbol\textnoway{"26D4}
\DeclareUTFSymbol\textMountain{"26F0}
\DeclareUTFSymbol\textTent{"26FA}
\DeclareUTFSymbol\textScissorRightBrokenBottom{"2701}
\DeclareUTFSymbol\textScissorRight{"2702}
\DeclareUTFSymbol\textScissorRightBrokenTop{"2703}
\DeclareUTFSymbol\textScissorHollowRight{"2704}
\DeclareUTFSymbol\textPhoneHandset{"2706}
\DeclareUTFSymbol\textTape{"2707}
\DeclareUTFSymbol\textPlane{"2708}
\DeclareUTFSymbol\textEnvelope{"2709}
\DeclareUTFSymbol\textPeace{"270C}
\DeclareUTFSymbol\textWritingHand{"270D}
\DeclareUTFSymbol\textPencilRightDown{"270E}
\DeclareUTFSymbol\textPencilRight{"270F}
\DeclareUTFSymbol\textPencilRightUp{"2710}
\DeclareUTFSymbol\textNibRight{"2711}
\DeclareUTFSymbol\textNibSolidRight{"2712}
\DeclareUTFSymbol\textCheckmark{"2713}
\DeclareUTFSymbol\textCheckmarkBold{"2714}
\DeclareUTFSymbol\textXSolid{"2715}
\DeclareUTFSymbol\textXSolidBold{"2716}
\DeclareUTFSymbol\textXSolidBrush{"2717}
\DeclareUTFSymbol\textPlusOutline{"2719}
\DeclareUTFSymbol\textPlus{"271A}
\DeclareUTFSymbol\textPlusThinCenterOpen{"271B}
\DeclareUTFSymbol\textPlusCenterOpen{"271C}
\DeclareUTFSymbol\textCross{"271D}
\DeclareUTFSymbol\textCrossOpenShadow{"271E}
\DeclareUTFSymbol\textCrossOutline{"271F}
\DeclareUTFSymbol\textCrossMaltese{"2720}
\DeclareUTFSymbol\textDavidStar{"2721}
\DeclareUTFSymbol\textFourAsterisk{"2722}
\DeclareUTFSymbol\textJackStar{"2723}
\DeclareUTFSymbol\textJackStarBold{"2724}
\DeclareUTFSymbol\textClowerTips{"2725}
\DeclareUTFSymbol\textFourStar{"2726}
\DeclareUTFSymbol\textFourStarOpen{"2727}
\DeclareUTFSymbol\textFiveStarOpenCircled{"272A}
\DeclareUTFSymbol\textFiveStarCenterOpen{"272B}
\DeclareUTFSymbol\textFiveStarOpenDotted{"272C}
\DeclareUTFSymbol\textFiveStarOutline{"272D}
\DeclareUTFSymbol\textFiveStarOutlineHeavy{"272E}
\DeclareUTFSymbol\textFiveStarConvex{"272F}
\DeclareUTFSymbol\textFiveStarShadow{"2730}
\DeclareUTFSymbol\textAsteriskBold{"2731}
\DeclareUTFSymbol\textAsteriskCenterOpen{"2732}
\DeclareUTFSymbol\textEightStarTaper{"2734}
\DeclareUTFSymbol\textEightStarConvex{"2735}
\DeclareUTFSymbol\textSixStar{"2736}
\DeclareUTFSymbol\textEightStar{"2737}
\DeclareUTFSymbol\textEightStarBold{"2738}
\DeclareUTFSymbol\textTwelveStar{"2739}
\DeclareUTFSymbol\textSixteenStarLight{"273A}
\DeclareUTFSymbol\textSixFlowerPetalRemoved{"273B}
\DeclareUTFSymbol\textSixFlowerOpenCenter{"273C}
\DeclareUTFSymbol\textAsterisk{"273D}
\DeclareUTFSymbol\textSixFlowerAlternate{"273E}
\DeclareUTFSymbol\textFiveFlowerPetal{"273F}
\DeclareUTFSymbol\textFiveFlowerOpen{"2740}
\DeclareUTFSymbol\textEightFlowerPetal{"2741}
\DeclareUTFSymbol\textSunshineOpenCircled{"2742}
\DeclareUTFSymbol\textSixFlowerAltPetal{"2743}
\DeclareUTFSymbol\textSnowflakeChevron{"2744}
\DeclareUTFSymbol\textSnowflake{"2745}
\DeclareUTFSymbol\textSnowflakeChevronBold{"2746}
\DeclareUTFSymbol\textSparkle{"2747}
\DeclareUTFSymbol\textSparkleBold{"2748}
\DeclareUTFSymbol\textAsteriskRoundedEnds{"2749}
\DeclareUTFSymbol\textEightFlowerPetalRemoved{"274A}
\DeclareUTFSymbol\textEightAsterisk{"274B}
\DeclareUTFSymbol\textCircleShadow{"274D}
\DeclareUTFSymbol\textSquareShadowBottomRight{"274F}
\DeclareUTFSymbol\textSquareTopRight{"2750}
\DeclareUTFSymbol\textSquareCastShadowBottomRight{"2751}
\DeclareUTFSymbol\textSquareCastShadowTopRight{"2752}
\DeclareUTFSymbol\textDiamandSolid{"2756}
\DeclareUTFSymbol\textRectangleThin{"2758}
\DeclareUTFSymbol\textRectangle{"2759}
\DeclareUTFSymbol\textRectangleBold{"275A}
\DeclareUTFSymbol\textperp{"27C2}
\DeclareUTFCommand\textnotperp{\textlstrikethru\textperp}
\DeclareUTFSymbol\textveedot{"27C7}
\DeclareUTFSymbol\textwedgedot{"27D1}
\DeclareUTFSymbol\textleftspoon{"27DC}
\DeclareUTFSymbol\textlbrackdbl{"27E6}
\DeclareUTFSymbol\textrbrackdbl{"27E7}
\DeclareUTFSymbol\textcirclearrowleft{"27F2}
\DeclareUTFSymbol\textcirclearrowright{"27F3}
\DeclareUTFSymbol\textlongleftarrow{"27F5}
\DeclareUTFSymbol\textlongrightarrow{"27F6}
\DeclareUTFSymbol\textlongleftrightarrow{"27F7}
\DeclareUTFSymbol\textLongleftarrow{"27F8}
\DeclareUTFSymbol\textLongrightarrow{"27F9}
\DeclareUTFSymbol\textLongleftrightarrow{"27FA}
\DeclareUTFSymbol\textlongmapsto{"27FC}
\DeclareUTFSymbol\textLongmapsfrom{"27FD}
\DeclareUTFSymbol\textLongmapsto{"27FE}
\DeclareUTFSymbol\textnwsearrow{"2921}
\DeclareUTFSymbol\textneswarrow{"2922}
\DeclareUTFSymbol\textlhooknwarrow{"2923}
\DeclareUTFSymbol\textrhooknearrow{"2924}
\DeclareUTFSymbol\textlhooksearrow{"2925}
\DeclareUTFSymbol\textrhookswarrow{"2926}
\DeclareUTFSymbol\textleadsto{"2933}
\DeclareUTFSymbol\textrcurvearrowne{"2934}
\DeclareUTFSymbol\textlcurvearrowse{"2935}
\DeclareUTFSymbol\textlcurvearrowsw{"2936}
\DeclareUTFSymbol\textrcurvearrowse{"2937}
\DeclareUTFSymbol\textlcurvearrowdown{"2938}
\DeclareUTFSymbol\textrcurvearrowdown{"2939}
\DeclareUTFSymbol\textrcurvearrowleft{"293A}
\DeclareUTFSymbol\textrcurvearrowright{"293B}
\DeclareUTFSymbol\textleftrightharpoon{"294A}
\DeclareUTFSymbol\textrightleftharpoon{"294B}
\DeclareUTFSymbol\textupdownharpoonrightleft{"294C}
\DeclareUTFSymbol\textupdownharpoonleftright{"294D}
\DeclareUTFSymbol\textleftleftharpoons{"2962}
\DeclareUTFSymbol\textupupharpoons{"2963}
\DeclareUTFSymbol\textrightrightharpoons{"2964}
\DeclareUTFSymbol\textdowndownharpoons{"2965}
\DeclareUTFSymbol\textleftbarharpoon{"296A}
\DeclareUTFSymbol\textbarleftharpoon{"296B}
\DeclareUTFSymbol\textrightbarharpoon{"296C}
\DeclareUTFSymbol\textbarrightharpoon{"296D}
\DeclareUTFSymbol\textupdownharpoons{"296E}
\DeclareUTFSymbol\textdownupharpoons{"296F}
\DeclareUTFSymbol\textllparenthesis{"2987}
\DeclareUTFSymbol\textrrparenthesis{"2988}
\DeclareUTFSymbol\textinvdiameter{"29B0}
\DeclareUTFSymbol\textobar{"29B6}
\DeclareUTFSymbol\textobslash{"29B8}
\DeclareUTFSymbol\textobot{"29BA}
\DeclareUTFSymbol\textNoChemicalCleaning{"29BB}
\DeclareUTFSymbol\textolessthan{"29C0}
\DeclareUTFSymbol\textogreaterthan{"29C1}
\DeclareUTFSymbol\textboxslash{"29C4}
\DeclareUTFSymbol\textboxbslash{"29C5}
\DeclareUTFSymbol\textboxast{"29C6}
\DeclareUTFSymbol\textboxcircle{"29C7}
\DeclareUTFSymbol\textboxbox{"29C8}
\DeclareUTFSymbol\textValve{"29D3}
\DeclareUTFSymbol\textmultimapboth{"29DF}
\DeclareUTFSymbol\textshuffle{"29E2}
\DeclareUTFSymbol\textuplus{"2A04}
\DeclareUTFSymbol\textbigdoublewedge{"2A07}
\DeclareUTFSymbol\textbigdoublevee{"2A08}
\DeclareUTFSymbol\textJoin{"2A1D}
\DeclareUTFSymbol\textfatsemi{"2A1F}
\DeclareUTFSymbol\textcircplus{"2A22}
\DeclareUTFSymbol\textminusdot{"2A2A}
\DeclareUTFSymbol\textdottimes{"2A30}
\DeclareUTFSymbol\textdtimes{"2A32}
\DeclareUTFSymbol\textodiv{"2A38}
\DeclareUTFSymbol\textinvneg{"2A3C}
\DeclareUTFSymbol\textsqdoublecap{"2A4E}
\DeclareUTFSymbol\textcapdot{"2A40}
\DeclareUTFSymbol\textsqdoublecup{"2A4F}
\DeclareUTFSymbol\textdoublewedge{"2A55}
\DeclareUTFSymbol\textdoublevee{"2A56}
\DeclareUTFSymbol\textdoublebarwedge{"2A5E}
\DeclareUTFSymbol\textveedoublebar{"2A63}
\DeclareUTFSymbol\texteqdot{"2A66}
\DeclareUTFCommand\textneqdot{\textlstrikethru\texteqdot}
\DeclareUTFSymbol\textcoloncolonequals{"2A74}
\DeclareUTFSymbol\textleqslant{"2A7D}
\DeclareUTFCommand\textnleqslant{\textlstrikethrux\textleqslant}
\DeclareUTFSymbol\textgeqslant{"2A7E}
\DeclareUTFCommand\textngeqslant{\textlstrikethru\textgeqslant}
\DeclareUTFSymbol\textlessapprox{"2A85}
\DeclareUTFCommand\textnlessapprox{\textlstrikethru\textnlessapprox}
\DeclareUTFSymbol\textgtrapprox{"2A86}
\DeclareUTFCommand\textngtrapprox{\textlstrikethru\textgtrapprox}
\DeclareUTFSymbol\textlneq{"2A87}
\DeclareUTFSymbol\textgneq{"2A88}
\DeclareUTFSymbol\textlnapprox{"2A89}
\DeclareUTFSymbol\textgnapprox{"2A8A}
\DeclareUTFSymbol\textlesseqqgtr{"2A8B}
\DeclareUTFSymbol\textgtreqqless{"2A8C}
\DeclareUTFSymbol\texteqslantless{"2A95}
\DeclareUTFSymbol\texteqslantgtr{"2A96}
\DeclareUTFSymbol\textleftslice{"2AA6}
\DeclareUTFSymbol\textrightslice{"2AA7}
\DeclareUTFSymbol\textpreceq{"2AAF}
\DeclareUTFCommand\textnpreceq{\textlstrikethru\textpreceq}
\DeclareUTFSymbol\textsucceq{"2AB0}
\DeclareUTFCommand\textnsucceq{\textlstrikethru\textsucceq}
\DeclareUTFSymbol\textprecneq{"2AB1}
\DeclareUTFSymbol\textsuccneq{"2AB2}
\DeclareUTFSymbol\textpreceqq{"2AB3}
\DeclareUTFCommand\textnpreceqq{\textlstrikethru\textpreceqq}
\DeclareUTFSymbol\textsucceqq{"2AB4}
\DeclareUTFCommand\textnsucceqq{\textlstrikethru\textsucceqq}
\DeclareUTFSymbol\textprecneqq{"2AB5}
\DeclareUTFSymbol\textsuccneqq{"2AB6}
\DeclareUTFSymbol\textprecapprox{"2AB7}
\DeclareUTFCommand\textnprecapprox{\textlstrikethru\textprecapprox}
\DeclareUTFSymbol\textsuccapprox{"2AB8}
\DeclareUTFCommand\textnsuccapprox{\textlstrikethru\textsuccapprox}
\DeclareUTFSymbol\textprecnapprox{"2AB9}
\DeclareUTFSymbol\textsuccnapprox{"2ABA}
\DeclareUTFSymbol\textsubseteqq{"2AC5}
\DeclareUTFCommand\textnsubseteqq{\textlstrikethru\textsubseteqq}
\DeclareUTFSymbol\textsupseteqq{"2AC6}
\DeclareUTFCommand\textnsupseteqq{\textlstrikethru\textsupseteqq}
\DeclareUTFSymbol\textdashV{"2AE3}
\DeclareUTFCommand\textndashV{\textlstrikethru\textdashV}
\DeclareUTFSymbol\textDashv{"2AE4}
\DeclareUTFCommand\textnDashv{\textlstrikethru\textDashv}
\DeclareUTFSymbol\textDashV{"2AE5}
\DeclareUTFCommand\textnDashV{\textlstrikethru\textDashV}
\DeclareUTFSymbol\textdownmodels{"2AEA}
\DeclareUTFCommand\textndownmodels{\textlstrikethru\textdownmodels}
\DeclareUTFSymbol\textupmodels{"2AEB}
\DeclareUTFCommand\textnupmodels{\textlstrikethru\textupmodels}
\DeclareUTFSymbol\textupspoon{"2AEF}
\DeclareUTFSymbol\textinterleave{"2AF4}
\DeclareUTFSymbol\textsslash{"2AFD}
\DeclareUTFSymbol\textpentagon{"2B20}
\DeclareUTFSymbol\textvarhexagon{"2B21}
\DeclareUTFSymbol\textjinferior{"2C7C}
\DeclareUTFSymbol\textslashdiv{"2E13}
\DeclareUTFSymbol\textinterrobangdown{"2E18}
\DeclareUTFSymbol\textfivedots{"2E2D}
\DeclareUTFSymbol\textPUheng{"A727}
\DeclareUTFSymbol\textPUlhookfour{"A72C}
\DeclareUTFSymbol\textPUscf{"A730}
\DeclareUTFSymbol\textPUaolig{"A735}
\DeclareUTFSymbol\textoo{"A74F}
\DeclareUTFSymbol\textcircumlow{"A788}
\DeclareUTFSymbol\textfi{"FB01}
\DeclareUTFSymbol\textfl{"FB02}
\DeclareUTFSymbol\textGaPa{"1D13B}
\DeclareUTFSymbol\textHaPa{"1D13C}
\DeclareUTFSymbol\textViPa{"1D13D}
\DeclareUTFSymbol\textAcPa{"1D13E}
\DeclareUTFSymbol\textSePa{"1D13F}
\DeclareUTFSymbol\textZwPa{"1D140}
\DeclareUTFSymbol\textfullnote{"1D15D}
\DeclareUTFSymbol\texthalfnote{"1D15E}
\DeclareUTFSymbol\textVier{"1D15F}
\DeclareUTFSymbol\textAcht{"1D160}
\DeclareUTFSymbol\textSech{"1D161}
\DeclareUTFSymbol\textZwdr{"1D162}
\DeclareUTFSymbol\textMundus{"1F30D}
\DeclareUTFSymbol\textMoon{"1F319}
\DeclareUTFSymbol\textManFace{"1F468}
\DeclareUTFSymbol\textWomanFace{"1F469}
\DeclareUTFSymbol\textFax{"1F4E0}
\DeclareUTFSymbol\textFire{"1F525}
\DeclareUTFSymbol\textBicycle{"1F6B2}
\DeclareUTFSymbol\textGentsroom{"1F6B9}
\DeclareUTFSymbol\textLadiesroom{"1F6BA}
\DeclareUTFCommand\textcopyleft{\textcircled\textrevc}
\DeclareUTFCommand\textccsa{\textcircled\textcirclearrowleft}
\DeclareUTFSymbol\textglqq{"201E}
\DeclareUTFSymbol\textgrqq{"201C}
\DeclareUTFSymbol\textglq{"201A}
\DeclareUTFSymbol\textgrq{"2018}
\DeclareUTFSymbol\textflqq{"00AB}
\DeclareUTFSymbol\textfrqq{"00BB}
\DeclareUTFSymbol\textflq{"2039}
\DeclareUTFSymbol\textfrq{"203A}
\DeclareUTFSymbol\textneg{"00AC}
\DeclareUTFSymbol\textcdot{"00B7}
%    \end{macrocode}
%
%    \begin{macrocode}
%</xunextra>
%    \end{macrocode}
%
% \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno
%    \begin{macrocode}
%<@@=xeCJK>
%    \end{macrocode}\egroup
%
% \subsection{\pkg{xeCJK.cfg}}
%
%    \begin{macrocode}
%<*config>
%    \end{macrocode}
%
% 预设的配置文件 \file{xeCJK.cfg} 为一个空文件。可以在里面增加设置，然后保存到
% 本地目录下面。
%    \begin{macrocode}

%    \end{macrocode}
%
%    \begin{macrocode}
%</config>
%    \end{macrocode}
%
% \begin{comment}
%
% \makeatletter
% \let\special@index\@gobble
% \makeatother
%
% \section{例子}
%
% \subsection{\pkg{xeCJK-example-autofake.tex}}
%
%    \begin{macrocode}
%<*ex-autofake>
%    \end{macrocode}
%
%    \begin{macrocode}
\documentclass{article}
\usepackage[AutoFakeBold,AutoFakeSlant]{xeCJK}
\setCJKmainfont[BoldFont=simhei.ttf, SlantedFont=simkai.ttf]{simsun.ttc}
\setCJKsansfont[AutoFakeSlant=false,
  BoldFont=simhei.ttf, SlantedFont=simkai.ttf]{simsun.ttc}
\setCJKmonofont[ItalicFont=simkai.ttf]{simsun.ttc}
\begin{document}
\centering
\begin{tabular}{lllll}
\hline
 {\bf rm} & md & up & \verb|\rmfamily\mdseries\upshape| &
                      {\rmfamily\mdseries\upshape English 中文字体} \\
          & md & it & \verb|\rmfamily\mdseries\itshape| &
                      {\rmfamily\mdseries\itshape English 中文字体} \\
          & md & sl & \verb|\rmfamily\mdseries\slshape| &
                      {\rmfamily\mdseries\slshape English 中文字体} \\ \cline{2-5}
          & bf & up & \verb|\rmfamily\bfseries\upshape| &
                      {\rmfamily\bfseries\upshape English 中文字体} \\
          & bf & it & \verb|\rmfamily\bfseries\itshape| &
                      {\rmfamily\bfseries\itshape English 中文字体} \\
          & bf & sl & \verb|\rmfamily\bfseries\slshape| &
                      {\rmfamily\bfseries\slshape English 中文字体} \\ \hline
 {\bf sf} & md & up & \verb|\sffamily\mdseries\upshape| &
                      {\sffamily\mdseries\upshape English 中文字体} \\
          & md & it & \verb|\sffamily\mdseries\itshape| &
                      {\sffamily\mdseries\itshape English 中文字体} \\
          & md & sl & \verb|\sffamily\mdseries\slshape| &
                      {\sffamily\mdseries\slshape English 中文字体} \\ \cline{2-5}
          & bf & up & \verb|\sffamily\bfseries\upshape| &
                      {\sffamily\bfseries\upshape English 中文字体} \\
          & bf & it & \verb|\sffamily\bfseries\itshape| &
                      {\sffamily\bfseries\itshape English 中文字体} \\
          & bf & sl & \verb|\sffamily\bfseries\slshape| &
                      {\sffamily\bfseries\slshape English 中文字体} \\ \hline
 {\bf tt} & md & up & \verb|\ttfamily\mdseries\upshape| &
                      {\ttfamily\mdseries\upshape English 中文字体} \\
          & md & it & \verb|\ttfamily\mdseries\itshape| &
                      {\ttfamily\mdseries\itshape English 中文字体} \\
          & md & sl & \verb|\ttfamily\mdseries\slshape| &
                      {\ttfamily\mdseries\slshape English 中文字体} \\ \cline{2-5}
          & bf & up & \verb|\ttfamily\bfseries\upshape| &
                      {\ttfamily\bfseries\upshape English 中文字体} \\
          & bf & it & \verb|\ttfamily\bfseries\itshape| &
                      {\ttfamily\bfseries\itshape English 中文字体} \\
          & bf & sl & \verb|\ttfamily\bfseries\slshape| &
                      {\ttfamily\bfseries\slshape English 中文字体} \\ \hline
\end{tabular}
\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</ex-autofake>
%    \end{macrocode}
%
% \subsection{\pkg{xeCJK-example-fallback.tex}}
%
%    \begin{macrocode}
%<*ex-fallback>
%    \end{macrocode}
%
%    \begin{macrocode}
\documentclass{article}
\usepackage[AutoFallBack]{xeCJK}
\usepackage{xeCJKfntef}
\usepackage{array}
\setCJKmainfont[AutoFakeBold,AutoFakeSlant]{KaiTi_GB2312}
\setCJKfallbackfamilyfont{\CJKrmdefault}[BoldFont=SimHei]
  { [SlantedFont=FangSong]{SimSun} ,
    [BoldFont=*]          {SimSun-ExtB} }
\begin{document}
漢字源𣴑考

\textbf{漢字源𣴑考}

\textsl{漢字源𣴑考}

\CJKunderwave{漢字源𣴑考}
\begin{table}[ht]
\caption{生僻字测试}
\medskip\centering
\begin{tabular}{*4{|c>{\ttfamily U+}l}|}
㐀 & 3400  & 㐁 & 3401  & 㐂 & 3402  & 㐃 & 3403  \\
㐄 & 3404  & 㐅 & 3405  & 㐆 & 3406  & 㐇 & 3407  \\
㐈 & 3408  & 㐉 & 3409  & 㐊 & 340A  & 㐋 & 340B  \\
㐌 & 340C  & 㐍 & 340D  & 㐎 & 340E  & 㐏 & 341F  \\
㐐 & 3410  & 㐑 & 3411  & 㐒 & 3412  & 㐓 & 3413  \\
㐔 & 3414  & 㐕 & 3415  & 㐖 & 3416  & 㐗 & 3417  \\
㐘 & 3418  & 㐙 & 3419  & 㐚 & 341A  & 㐛 & 341B  \\
㐜 & 341C  & 㐝 & 341D  & 㐞 & 341E  & 㐟 & 341F  \\[1ex]
𠀀 & 20000 & 𠀁 & 20001 & 𠀂 & 20002 & 𠀃 & 20003 \\
𠀄 & 20004 & 𠀅 & 20005 & 𠀆 & 20006 & 𠀇 & 20007 \\
𠀈 & 20008 & 𠀉 & 20009 & 𠀊 & 2000A & 𠀋 & 2000B \\
𠀌 & 2000C & 𠀍 & 2000D & 𠀎 & 2000E & 𠀏 & 2000F \\
𠀐 & 20010 & 𠀑 & 20011 & 𠀒 & 20012 & 𠀓 & 20013 \\
𠀔 & 20014 & 𠀕 & 20015 & 𠀖 & 20016 & 𠀗 & 20017 \\
𠀘 & 20018 & 𠀙 & 20019 & 𠀚 & 2001A & 𠀛 & 2001B \\
𠀜 & 2001C & 𠀝 & 2001D & 𠀞 & 2001E & 𠀟 & 2001F \\
\end{tabular}
\end{table}
\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</ex-fallback>
%    \end{macrocode}
%
% \subsection{\pkg{xeCJK-example-subCJKblock.tex}}
%
%    \begin{macrocode}
%<*ex-block>
%    \end{macrocode}
%
%    \begin{macrocode}
\documentclass{article}
\usepackage{xeCJK}
\usepackage{array}
\xeCJKDeclareSubCJKBlock{Ext-A} { "3400 -> "4DBF }
\xeCJKDeclareSubCJKBlock{Ext-B} { "20000 -> "2A6DF }
\xeCJKDeclareSubCJKBlock{Kana}  { "3040 -> "309F, "30A0 -> "30FF, "31F0 -> "31FF, }
\xeCJKDeclareSubCJKBlock{Hangul}{ "1100 -> "11FF, "3130 -> "318F, "A960 -> "A97F, "AC00 -> "D7AF }
\setCJKmainfont[Ext-A=SimHei,Ext-B=SimSun-ExtB]{SimSun}
\setCJKmainfont[Kana]{Meiryo}
\setCJKmainfont[Hangul]{Malgun Gothic}
\parindent=2em
\begin{document}
\long\def\showtext{%
中日韩越统一表意文字（英语：CJKV Unified Ideographs），旧称中日韩统一表意文字（英语：CJK Unified Ideographs），也称统一汉字（英语：Unihan），目的是要把分别来自中文、日文、韩文、越文、壮文中，对于相同起源、本义相同、形状一样或稍异的表意文字（主要为汉字，但也有仿汉字如：方块壮字、日文汉字（かんじ / kanji）、韩文汉字（한자 / hanja）、越南的喃字（Chữ Nôm）与越文汉字（Chữ Nho，在越南也称作儒字），应赋予其在ISO 10646及统一码标准中有相同编码。此计划原本只包含中文、日文及韩文中所使用的汉字，是以旧称中日韩统一表意文字（CJK）。后来，此计划加入了越文的喃字，所以合称中日韩越统一表意文字（CJKV）。

CJK統合漢字（シージェーケーとうごうかんじ、CJK Unified Ideographs）は、ISO/IEC 10646 (Universal Multiple-Octet Coded Character Set, 略称 UCS) および Unicodeにて採用されている符号化用漢字集合およびその符号表である。CJK統合漢字の名称は、中国語(Chinese)、日本語(Japanese)、韓国語(Korean)で使われている漢字をひとまとめにしたことからきている。CJK統合漢字の初版である Unified Repertoire and Ordering (URO) 第二版は1992年に制定されたが、1994年にベトナムで使われていた漢字も含めることにしたため、CJKVと呼ばれる事もある。CJKVは、中国語・日本語・韓国語・ベトナム語 (英語: Chinese-Japanese-Korean-Vietnamese) の略。特に、その4言語で共通して使われる、または使われていた文字体系である漢字（チュノムを含む）のこと。ソフトウェアの国際化、中でも文字コードに関する分野で用いられる。

\CJKspace
한중일월 통합 한자(또는 한중일 통합 한자)는 유니코드에 담겨 있는 한자들의 집합으로, 한국, 중국, 일본에서 쓰이는 한자를 묶은 것이기 때문에 머리 글자를 따서 한중일(CJK) 통합 한자라고 불렀는데, 최근에는 베트남에서 쓰이는 한자도 추가되었기에 한중일월(CJKV) 통합 한자로 부르게 되었다.

처음에 유니코드에는 65,536($=2^{16}$)자만 들어갈 수 있었기 때문에, 가장 많은 문자가 배당되는 한자를 위해서 한국, 중국, 일본에서 사용하는 한자 중에 모양이 유사하며 그 뜻이 같은 글자를 같은 코드로 통합했다. 따라서 문자 코드만으로 그 한자가 사용되는 언어를 알아 낼 수 없는데, 다만 중국의 간체자나 번체자, 일본의 구자체나 신자체 등 분명하게 모양이 다른 글자는 별도의 부호를 할당하고 있다. 이런 문자 할당 정책에 반발하여 TRON과 같은 인코딩이 만들어지기도 했으나, 실제로 통합된 한자의 차이가 별로 크지 않기 때문에 문제가 되지 않는다는 의견도 있다.
\CJKnospace}
\showtext

\bigskip
\xeCJKCancelSubCJKBlock{Kana,Hangul}
\showtext

\bigskip
\xeCJKRestoreSubCJKBlock{Hangul}
\showtext

\begin{table}[ht]
\caption{生僻字测试}
\medskip\centering
\begin{tabular}{*4{|c>{\ttfamily U+}l}|}
㐀 & 3400  & 㐁 & 3401  & 㐂 & 3402  & 㐃 & 3403  \\
㐄 & 3404  & 㐅 & 3405  & 㐆 & 3406  & 㐇 & 3407  \\
㐈 & 3408  & 㐉 & 3409  & 㐊 & 340A  & 㐋 & 340B  \\
㐌 & 340C  & 㐍 & 340D  & 㐎 & 340E  & 㐏 & 341F  \\
㐐 & 3410  & 㐑 & 3411  & 㐒 & 3412  & 㐓 & 3413  \\
㐔 & 3414  & 㐕 & 3415  & 㐖 & 3416  & 㐗 & 3417  \\
㐘 & 3418  & 㐙 & 3419  & 㐚 & 341A  & 㐛 & 341B  \\
㐜 & 341C  & 㐝 & 341D  & 㐞 & 341E  & 㐟 & 341F  \\[1ex]
𠀀 & 20000 & 𠀁 & 20001 & 𠀂 & 20002 & 𠀃 & 20003 \\
𠀄 & 20004 & 𠀅 & 20005 & 𠀆 & 20006 & 𠀇 & 20007 \\
𠀈 & 20008 & 𠀉 & 20009 & 𠀊 & 2000A & 𠀋 & 2000B \\
𠀌 & 2000C & 𠀍 & 2000D & 𠀎 & 2000E & 𠀏 & 2000F \\
𠀐 & 20010 & 𠀑 & 20011 & 𠀒 & 20012 & 𠀓 & 20013 \\
𠀔 & 20014 & 𠀕 & 20015 & 𠀖 & 20016 & 𠀗 & 20017 \\
𠀘 & 20018 & 𠀙 & 20019 & 𠀚 & 2001A & 𠀛 & 2001B \\
𠀜 & 2001C & 𠀝 & 2001D & 𠀞 & 2001E & 𠀟 & 2001F \\
\end{tabular}
\end{table}
\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</ex-block>
%    \end{macrocode}
%
%
% \subsection{\pkg{xeCJK-example-CJKecglue.tex}}
%
%    \begin{macrocode}
%<*ex-ecglue>
%    \end{macrocode}
%
%    \begin{macrocode}
\documentclass{minimal}
\usepackage{xeCJK}
\setCJKmainfont[BoldFont=SimHei]{SimSun}
\long\def\showtext{%
 这是 English 中文 {\itshape Chinese} 中文    \TeX\
  间隔 \textit{Italic} 中文\textbf{字体} a 数学 $b$ 数学 $c$ $d$\par
 这是English中文{\itshape Chinese}中文\TeX\
 间隔\textit{Italic}中文\textbf{字体}a数学$b$数学$c$ $d$\par
This is an example. 这是一个例子}
\begin{document}
\showtext

\hrulefill\bigskip

\xeCJKsetup{xCJKecglue=\quad}
\showtext
\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</ex-ecglue>
%    \end{macrocode}
%
% \subsection{\pkg{xeCJK-example-checksingle.tex}}
%
%    \begin{macrocode}
%<*ex-single>
%    \end{macrocode}
%
%    \begin{macrocode}
\documentclass{minimal}
\usepackage{xeCJK}
\setCJKmainfont{SimSun}
\catcode`\。=\active
\def。{．}
\def\foo{一}
\long\def\showtext{一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十。
\[x^2+y^2\]
一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十\foo
$$x^2+y^2$$
一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十\foo
\begin{equation}
x^2+y^2
\end{equation}
一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十。}
\begin{document}
\hsize=30em
\parindent=0pt
\showtext

\hrulefill\bigskip

\xeCJKsetup{CheckSingle}
\showtext

\hrulefill\bigskip

\xeCJKsetup{PlainEquation}
\showtext
\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</ex-single>
%    \end{macrocode}
%
% \subsection{\pkg{xeCJK-example-CJKfntef.tex}}
%
%    \begin{macrocode}
%<*ex-fntef>
%    \end{macrocode}
%
%    \begin{macrocode}
\documentclass{ctexart}
\usepackage{xcolor}
\usepackage{xeCJKfntef}
\xeCJKDeclareSubCJKBlock{test}{ `殆 , `已 }
\setCJKmainfont[test=SimHei]{SimSun}

\def\showtext{%
  庄子曰：“吾生也有涯，而知也无涯。以有涯随无涯，殆已！已而为知者，殆而已矣！%
  为善无近名，为恶无近刑，缘督以为经，可以保身，可以全生，可以养亲，可以尽年。”}
\newcommand\CJKfntef[1]{%
  \csname#1\endcsname{\showtext}\par
  \csname#1\endcsname*{\showtext}\par
  \CJKunderdot{\showtext\csname#1\endcsname{\showtext}}\par
  \CJKunderdot{\showtext\csname#1\endcsname*{\showtext}}\par
  \csname#1\endcsname{\showtext\CJKunderdot{\showtext}}\par
  \csname#1\endcsname*{\showtext\CJKunderdot{\showtext}}\par\bigskip}

\begin{document}

\section{\textsf{xeCJKfntef} 的\CJKunderdot{简单测试文件}}

\CJKunderline{汉 字}\CJKunderline{加下划线}
\varCJKunderline{汉字}\varCJKunderline{加下划线}
\CJKunderanyline{0.5em}{\sixly \kern-.021em\char58 \kern-.021em}{自定义下划线}
\CJKunderanyline{0.2em}{\kern-.03em\vtop{\kern.2ex\hrule width.2em\kern 0.11em
  \hrule height 0.1em}\kern-.03em}{自定义下划线}

\CJKunderanyline{0.5em}{-}{\showtext}

\CJKunderanysymbol{0.2em}{-}{\showtext}

\CJKunderdot{\showtext}

\hrule depth \dp\strutbox width 0 pt \relax

\begin{CJKfilltwosides}{40mm}
两端分散对齐\\
分散对齐\\
\CJKunderdot{汉字可加点}\\
\CJKunderline{汉字可加下划线}
\end{CJKfilltwosides}

\hrule depth \dp\strutbox width 0 pt \relax

\CJKfntef{CJKunderline}
\CJKfntef{CJKunderwave}
\CJKfntef{CJKunderdblline}
\CJKfntef{CJKsout}
\CJKfntef{CJKxout}

\def\Book{\CJKunderwave-}
\def\Noun{\CJKunderline-}

如上所述，\Book{中國文學史}原是\Noun{復旦大學出版社}出版的，\Book{中國文學史新著}則由\Noun{上海文藝出版社}出版。現承\Noun{復旦大學出版社}\Noun{賀聖遂}先生的盛情和\Noun{上海文藝出版總社}\Noun{楊益萍}、\Noun{何承偉}先生以及有關負責人\Noun{陳鳴華}先生的高誼，此書增訂本改由兩社聯合出版。\Noun{賀聖遂}先生並與\Noun{杜榮根}副社長、\Noun{韓結根}編審共同擔任此書的責任編輯。對上述諸位先生謹在這裡表示衷心的感謝。對\Book{中國文學史新著}原版的責任編輯\Noun{戴俊}先生（現為\Noun{上海三聯書店}副總經理）也在此一併致謝。

\Noun{與文學史的}\Noun{應有任務}\Noun{對文學發展過程}\Noun{的內在聯繫的描述}\Noun{還有很大的距離}\Noun{至於距離的所在}\Noun{本書原已有說明}\Book{此不贅述}\Book{為了對學術負責}\Book{我們決定重寫一部並迅即出版}

\Noun{南朝}\Noun{梁}\Noun{劉勰}\Book{文心雕龍}\Book{養氣}

\Noun{鎌池和馬}\Book{魔法禁書目錄}\Book{某科學的超電磁砲}

\Noun{西尾維新}\Book{化物語}\Book{偽物語}\Book{貓物語}%
\Book{傾物语}\Book{囤物語}\Book{鬼物語}\Book{戀物語}\Book{花物語}

\Noun{岡田麿里}\Book{我們仍未知道那天所看見的花的名字。}\Book{絕園的暴風雨}

\Noun{虚淵玄}\Book{Fate/Zero}\Book{PSYCHO-PASS}\Book{ALDNOAH.ZERO}

\Noun{劉海洋}\Book{\LaTeX 入門}

\def\NAME{%
  \x{御坂美琴}\x{白井黑子}\x{戰場原緋多木}\x{阿良良木歷}%
  \x{宿海仁太}\x{本間芽衣子}\x{瀧川吉野}\x{鎖部葉風}%
  \x{衛宮切嗣}\x{言峰綺禮}\x{常守朱}\x{狡嚙慎也}%
  \x{界塚伊奈帆}\x*{艾瑟依拉姆·沃斯·艾莉歐斯亞}}

\let\x\Noun\NAME

\let\x\Book\NAME

\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</ex-fntef>
%    \end{macrocode}
%
% \subsection{\pkg{xeCJK-example-punctstyle.tex}}
%
%    \begin{macrocode}
%<*ex-punctstyle>
%    \end{macrocode}
%
%    \begin{macrocode}
\documentclass{article}
\usepackage[draft,columns=1,margin=false,headings=false]{typogrid}
\usepackage{xeCJK}
\usepackage{xeCJKfntef}
\setCJKmainfont{SimSun}
\xeCJKsetup{AllowBreakBetweenPuncts}
\xeCJKDeclarePunctStyle { mine }
  {
    fixed-punct-ratio       = nan ,
    fixed-margin-width      = 0 pt ,
    mixed-margin-width      = \maxdimen ,
    mixed-margin-ratio      = 0.5 ,
    middle-margin-width     = \maxdimen ,
    middle-margin-ratio     = 0.5 ,
    add-min-bound-to-margin = true ,
    min-bound-to-kerning    = true ,
    kerning-margin-minimum  = 0.1 em ,
    bound-punct-width       = 0 em ,
    enabled-hanging         = true
  }
\xeCJKDeclarePunctStyle { JIS } { bound-punct-ratio = .5 }

\begin{document}
\setlength\parindent{2em}
\newcommand\showexample[1]{%
  \texttt{------ #1 ------}\par\xeCJKsetup{PunctStyle=#1}\showtexts\par}

\newcommand\showtexts{%
《第一回\quad 甄士隐梦幻识通灵\quad 贾雨村风尘怀闺秀》\\
《第一回\quad 甄士隐梦幻识通灵\quad 贾雨村风尘怀闺秀》

列位看官：你道此书从何而来？说起根由，虽近荒唐，细按则深有趣味。待在下将此来历注明，方使阅者了然不惑。

\CJKunderline*{原来女娲氏炼石补天之时，于大荒山无稽崖炼成高经十二丈、方经二十四丈顽石三万六千五百零一块。娲皇氏只用了三万六千五百块，只单单剩了一块未用，便弃在此山青埂峰下。谁知此石自经煆炼之后，灵性已通，因见众石俱得补天，独自己无材不堪入选，遂自怨自叹，日夜悲号惭愧。}

一日，正当嗟悼之际，俄见一僧一道远远而来，生得骨格不凡，丰神迥别，说说笑笑，来至峰下，坐于石边，高谈快论：先是说些云山雾海、神仙玄幻之事，后便说到红尘中荣华富贵。此石听了，不觉打动凡心，也想要到人间去享一享这荣华富贵，但自恨粗蠢，不得已，便口吐人言，向那僧道说道：“大师，弟子蠢物，不能见礼了！适闻二位谈那人世间荣耀繁华，心切慕之。弟子质虽粗蠢，性却稍通，况见二师仙形道体，定非凡品，必有补天济世之材，利物济人之德。如蒙发一点慈心，携带弟子得入红尘，在那富贵场中，温柔乡里受享几年，自当永佩洪恩，万劫不忘也！”二仙师听毕，齐憨笑道：“善哉，善哉！那红尘中有却有些乐事，但不能永远依恃；况又有‘美中不足，好事多磨’八个字紧相连属，瞬息间则又乐极悲生，人非物换，究竟是到头一梦，万境归空，倒不如不去的好。”这石凡心已炽，那里听得进这话去，乃复苦求再四。二仙知不可强制，乃叹道：“此亦静极思动，无中生有之数也！既如此，我们便携你去受享受享，只是到不得意时，切莫后悔！”石道：“自然，自然。”那僧又道：“若说你性灵，却又如此质蠢，并更无奇贵之处。如此也只好踮脚而已。也罢！我如今大施佛法，助你助，待劫终之日，复还本质，以了此案。你道好否？”石头听了，感谢不尽。那僧便念咒书符，大展幻术，将一块大石登时变成一块鲜明莹洁的美玉，且又缩成扇坠大小的可佩可拿。那僧托于掌上，笑道：“形体倒也是个宝物了！还只没有实在的好处，须得再镌上数字，使人一见便知是奇物方妙。然后好携你到那昌明隆盛之邦、诗礼簪缨之族、花柳繁华地、温柔富贵乡去安身乐业。”石头听了，喜不能禁，乃问：“不知赐了弟子那哪几件奇处？又不知携了弟子到何地方？望乞明示，使弟子不惑。”那僧笑道：“你且莫问，日后自然明白的。”说着，便袖了这石，同那道人飘然而去，竟不知投奔何方何舍。

\hfill
——曹雪芹《红楼梦》\unskip\unkern}


\showexample{mine}
\showexample{quanjiao}
\showexample{JIS}
\showexample{banjiao}
\showexample{CCT}
\showexample{kaiming}
\showexample{hangmobanjiao}
\showexample{plain}

\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</ex-punctstyle>
%    \end{macrocode}
%
% \subsection{\pkg{xeCJK-example-verbatim.tex}}
%
%    \begin{macrocode}
%<*ex-verb>
%    \end{macrocode}
%
%    \begin{macrocode}
\documentclass[a4paper]{article}
\usepackage{xeCJK}
\usepackage{fullpage}
\xeCJKDeclareSubCJKBlock{Hangul}
  { "1100 -> "11FF, "3130 -> "318F, "A960 -> "A97F, "AC00 -> "D7AF }
\setCJKmainfont{Adobe Song Std}
\setCJKmainfont[Hangul]{Adobe Myungjo Std}
%%\setmonofont{Inconsolata}
%%\setmonofont{Source Code Pro}
%%\setCJKmonofont{Adobe Kaiti Std}
\setmonofont{TeX Gyre Cursor}
\setCJKmonofont{Adobe Fangsong Std}
\begin{document}

\begin{verbatim}
*************************************************************
*                                                           *
*      精致甲版红楼梦 - 精致工作室特别奉献（2010年9月）     *
*                                                           *
*        GBK简体、GBK繁体、Big5繁体、PDF简体、PDF繁体       *
*                                                           *
*  为 GBK、Big5 特别度身订制，并经反复修订，方便纯文本阅读  *
*                                                           *
*  精致甲、乙版红楼梦下载专页                               *
*  http://www.speedy7.com/cn/stguru/gb2312/redmansions.htm  *
*  http://www.speedy7.com/cn/stguru/big5/redmansions.htm    *
*                                                           *
*  此电子文件可随意传播、发布、下载。                       *
*  传播时建议保留此版本说明供查阅与识别。                   *
*  未经修订者同意，不得将此版本用于商业用途。               *
*  如您对红楼梦不具深入了解，请勿随便修改其中的内容。       *
*                                                           *
*************************************************************
\end{verbatim}

\verb|a 汉 字 b|

\verb*|a 汉 字 b|

\begin{verbatim}
lang_set = {
  ["English"]   = lang.en,
  ["Français"]  = lang.fr,
  ["Español"]   = lang.es,
  ["中文"]      = lang.zh,
  ["日本語"]    = lang.ja,
  ["한국어"]    = lang.ko,
}
\end{verbatim}

\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</ex-verb>
%    \end{macrocode}
%
% \subsection{\pkg{xeCJK-example-IVS.tex}}
%
%    \begin{macrocode}
%<*ex-IVS>
%    \end{macrocode}
%
%    \begin{macrocode}
\documentclass{article}
\usepackage{xeCJK}
\usepackage{hologo}

\setCJKmainfont{HanaMinA} %% http://fonts.jp/hanazono/

\begin{document}

\hologo{XeTeX} でIVSを使うテスト。

消󠄀化󠄀器󠄂 / 消󠄁火器󠄃 / 消󠄂化󠄁器󠄄

消󠄃火器󠄅 / 消化󠄂器󠄆 / 消火器󠄇

消化󠄃器󠄈 / 消火器󠄉 / 辻󠄂辻󠄃辻󠄄辻󠄅　

\CJKfontspec{Meiryo}

か

がか゚

ぼぽ

ぼぽ

ばぱ

ばぱ

\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</ex-IVS>
%    \end{macrocode}
%
% \subsection{\pkg{xeCJK-example-listings.tex}}
%
%    \begin{macrocode}
%<*ex-listings>
%    \end{macrocode}
%
%    \begin{macrocode}
\documentclass{article}
\usepackage[margin=1in]{geometry}
\usepackage{listings,xcolor}
\usepackage{showexpl}

\usepackage{xeCJK}
\setCJKmainfont{HanaMinA}
\setCJKmonofont{SimSun}
\xeCJKDeclareSubCJKBlock{Kana}  { "3040 -> "309F, "30A0 -> "30FF, "31F0 -> "31FF }
\setCJKmonofont[Kana]{Meiryo}
\setmonofont{Latin Modern Mono Light}

\makeatletter
\lstset{%
  basicstyle=\small\ttfamily,breakindent=4\lst@width,
  numbers=left,numberstyle=\tiny\color{gray},
  commentstyle=\color{green!50!black},keywordstyle=\color{blue}\bfseries,
  identifierstyle=\color{violet},stringstyle=\color{brown},
  escapebegin=\normalfont}
\lstnewenvironment{cppcode}[1][]
  {\lstset{language=C++,#1}}
  {}
\makeatother

\begin{document}

\section{\lstinline{\\lstinline} 测试}

\section{\lstinline|甲*乙| 测试}

\lstinline|abc汉字abc|

\lstinline|甲*乙|

\lstinline[mathescape]|数学公式$x^2+y^2$|

\section{\lstinline{lstlisting} 环境测试}

\begin{lstlisting}[basicstyle=\rmfamily]
纯文字text测试
    纯文字text测试
文字+文字
文字（符号）文字
辻󠄂辻󠄃辻󠄄辻󠄅
かがか゚
\end{lstlisting}

\begin{lstlisting}
text纯文字测试
\end{lstlisting}

\begin{lstlisting}
text 纯文字测试
\end{lstlisting}

\begin{lstlisting}
text,纯文字测试
\end{lstlisting}

\section{自定义环境测试}

\begin{LTXexample}[pos=t,varwidth,numbersep=5pt,columns=fixed]
\begin{cppcode}[escapechar=`,morekeywords=返回]
#define 返回 return
#include <iostream>
/*
 * 块注释
 * `逃逸字符，测试$f(x)$`
 */
int main()
{
    // 行注释
    const char *欢迎 = "hello 世界（ワールド）";
    std::cout << 欢迎 << std::endl;
    返回 0;
}
\end{cppcode}
\end{LTXexample}

\section{\texttt{breaklines} 测试}

\begin{lstlisting}[linewidth=10em,frame=single,rulecolor=\color{black},breaklines]
断行文字text测试，断行文字text测试，断行文字text测试，断行文字text测试
断行文字text测试，断行文字text测试，断行文字text测试，断行文字text测试
\end{lstlisting}

\section{\lstinline|\\lstinputlisting| 测试}

\lstinputlisting[language={[AlLaTeX]TeX}]{\jobname}

\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</ex-listings>
%    \end{macrocode}
%
% \subsection{\pkg{xunicode-symbols.tex}}
%
%    \begin{macrocode}
%<*xunicode-symbols>
%    \end{macrocode}
%
% \setbox\xeCJKtmpbox\vbox\bgroup\gobblelineno
%    \begin{macrocode}
%<@@=xunsym>
%    \end{macrocode}\egroup
%
%    \begin{macrocode}
\documentclass{article}
\usepackage[margin=2cm]{geometry}
\usepackage{fontspec}
\usepackage{xunicode-addon}
\usepackage{l3str}
\usepackage{longtable,tabu,booktabs}
\usepackage{zref-base}

\setmainfont{FreeSerif}
\newfontfamily\falllbackfont{Segoe UI Symbol}

\makeatletter
\ExplSyntaxOn
\cs_new_protected_nopar:Npx \@@_restore_catcode:
  { \char_set_catcode:nn { \c_zero } { \char_value_catcode:n { \c_zero } } }
\file_if_exist:nTF { xunicode-commands.tex }
  { \char_set_catcode_comment:n { \c_zero } }
  { \char_set_catcode_ignore:n { \c_zero } }
^^@ \tl_new:N \l_@@_command_tl
^^@ \int_new:N \l_@@_command_int
^^@ \iow_new:N \g_@@_command_iow
^^@ \iow_new:N \g_@@_combine_mark_iow
^^@ \ior_new:N \g_@@_unicode_ior
^^@ \prop_new:N \l_@@_command_prop
^^@ \prop_new:N \l_@@_combine_mark_prop
^^@ \prop_new:N \l_@@_combine_marks_prop
^^@ \cs_new_protected_nopar:Npn \SaveUTFCommands
^^@   {
^^@     \group_begin:
^^@     \@@_restore_catcode:
^^@     \cs_set_eq:NN \DeclareTextAccent \use_none:nnn
^^@     \cs_set_eq:NN \DeclareUTFComposite \use_none:n
^^@     \cs_set_eq:NN \DeclareUTFEncodedAccent \use_none:nnn
^^@     \cs_set_eq:NN \DeclareUTFDoubleEncodedAccent \use_none:nnn
^^@     \cs_set_eq:NN \DeclareUTFDoubleEncodedSymbol \use_none:nnn
^^@     \cs_set_eq:NN \DeclareUTFCommand \use_none:nn
^^@     \cs_set_eq:NN \DeclareUTFTIPACommand \use_none:n
^^@     \cs_set_eq:NN \DeclareUTFCompositeCommand \use_none:nnn
^^@     \cs_set_eq:NN \DeclareUTFSymbol \@@_save_UTF_command:Nn
^^@     \cs_set_eq:NN \DeclareUTFCompositeSymbol \@@_save_UTF_command:Nnn
^^@     \cs_set_eq:NN \DeclareEncodedCompositeCharacter \@@_save_combine_mark:nnnn
^^@     \cs_set_eq:NN \DeclareEncodedCompositeAccents \@@_save_combine_marks:nnnn
^^@     \DeclareDocumentCommand \DeclareUTFcharacter { O { \UTFencname } m m }
^^@       { \@@_save_UTF_command:NNn \l_@@_command_prop {##3} {##2} }
^^@     \DeclareDocumentCommand \DeclareUTFcomposite { O { \UTFencname } m m m }
^^@       { \@@_save_UTF_command:NNnn \l_@@_command_prop {##3} {##4} {##2} }
^^@     \ReloadXunicode { \UTFencname }
^^@     \ior_open:NnTF \g_@@_unicode_ior { UnicodeData.txt }
^^@       {
^^@         \iow_open:Nn \g_@@_command_iow { xunicode-commands.tex }
^^@         \iow_open:Nn \g_@@_combine_mark_iow { xunicode-combine-marks.tex }
^^@         \ior_map_inline:Nn \g_@@_unicode_ior { \@@_make_table:w ##1 \q_stop }
^^@         \@@_write_combine_marks:
^^@         \ior_close:N \g_@@_unicode_ior
^^@         \iow_close:N \g_@@_command_iow
^^@         \iow_close:N \g_@@_combine_mark_iow
^^@         \group_end:
^^@       }
^^@       {
^^@         \group_end:
^^@         \msg_fatal:nn { @@ } { UnicodeData }
^^@       }
^^@   }
^^@ \msg_new:nnn { @@ } { UnicodeData }
^^@   { File~`UnicodeData.txt`~not~found. }
^^@ \cs_new_protected:Npn \@@_save_UTF_command:Nn
^^@   { \@@_save_UTF_command:NNn \l_@@_command_prop }
^^@ \cs_new_protected:Npn \@@_save_UTF_command:Nnn
^^@   { \@@_save_UTF_command:NNnn \l_@@_command_prop }
^^@ \cs_new_protected:Npn \@@_save_UTF_command:NNn #1#2#3
^^@   { \@@_save_UTF_text_command:Nxx #1 { \use_none:n #3 } { \token_to_str:N #2 } }
^^@ \cs_new_protected:Npn \@@_save_UTF_command:NNnn #1#2#3#4
^^@   {
^^@     \@@_save_UTF_text_command:Nxx #1 { \use_none:n #4 }
^^@       {
^^@         \token_to_str:N #2 \c_left_brace_str
^^@         \tl_if_single:nTF {#3} { \token_to_str:N #3 } { \tl_to_str:n {#3} }
^^@         \c_right_brace_str
^^@       }
^^@   }
^^@ \cs_new_protected:Npn \@@_save_combine_mark:nnnn #1#2#3#4
^^@   { \@@_save_UTF_text_command:Nxx \l_@@_combine_mark_prop {#3} { \token_to_str:N #2 } }
^^@ \cs_new_protected:Npn \@@_save_combine_marks:nnnn #1#2#3#4
^^@   { \@@_save_UTF_text_command:Nxx \l_@@_combine_marks_prop { { "#4 } { "#3 } } { \token_to_str:N #2 } }
^^@ \cs_new_protected:Npn \@@_save_UTF_text_command:Nxx #1#2#3
^^@   { \use:x { \@@_save_UTF_text_command:Nnn \exp_not:N #1 {#2} {#3} } }
^^@ \cs_new_protected:Npn \@@_save_UTF_text_command:Nnn #1#2#3
^^@   {
^^@     \prop_get:NnNTF #1 {#2} \l_@@_command_tl
^^@       { \prop_put:Nno #1 {#2} { \l_@@_command_tl , #3 } }
^^@       { \prop_put:Nnn #1 {#2} {#3} }
^^@   }
^^@ \cs_new_protected:Npn \@@_make_table:w #1 ; #2 ; #3 \q_stop
^^@   {
^^@     \prop_get:NnNT \l_@@_command_prop {#1} \l_@@_command_tl
^^@       {
^^@         \iow_now:Nx \g_@@_command_iow
^^@           { \token_to_str:N \UnicodeTextSymbol { "#1 } { \l_@@_command_tl } {#2} }
^^@       }
^^@     \prop_get:NnNT \l_@@_combine_mark_prop {#1} \l_@@_command_tl
^^@       {
^^@         \iow_now:Nx \g_@@_combine_mark_iow
^^@           { \token_to_str:N \UnicodeCombineMark { "#1 } { \l_@@_command_tl } {#2} }
^^@       }
^^@   }
^^@ \cs_new_protected:Npn \@@_write_combine_marks:
^^@   {
^^@     \prop_map_inline:Nn \l_@@_combine_marks_prop
^^@       {
^^@         \iow_now:Nx \g_@@_combine_mark_iow
^^@           { \token_to_str:N \UnicodeCombineMarks ##1 {##2} }
^^@       }
^^@   }
^^@ \ExplSyntaxOff
^^@ \SaveUTFCommands
^^@ \ExplSyntaxOn
\@@_restore_catcode:
\int_new:N \g_@@_symbol_int
\int_new:N \g_@@_table_int
\DeclareDocumentCommand \UnicodeTextSymbol { m v m }
  {
    \int_gincr:N \g_@@_symbol_int
    \use_none:n #1 &
    \scan_align_safe_stop:
    \reverse_if:N \etex_iffontchar:D \tex_font:D #1 \exp_stop_f: \falllbackfont \fi:
    \tex_char:D #1 \exp_stop_f: &
    \tl_set:Nn \l_tmpa_clist {#2}
    \clist_use:Nn \l_tmpa_clist { \par }
    \strut
    & #3 \\
  }
\cs_set_eq:NN \UnicodeCombineMark \UnicodeTextSymbol
\DeclareDocumentCommand \UnicodeCombineMarks { m m v }
  {
    \int_gincr:N \g_@@_symbol_int
    \use_none:n #1 ~ \use_none:n #2 &
    \tex_char:D #1 \exp_stop_f: \tex_char:D #2 \exp_stop_f: &
    \tl_set:Nn \l_tmpa_clist {#3}
    \clist_use:Nn \l_tmpa_clist { \par }
    \strut \\
  }
\DeclareDocumentCommand \UTFTABLE { m m }
  {
    \int_gincr:N \g_@@_table_int
    \exp_args:Nx \@@_make_table:nnn { UTFTABLE - \int_use:N \g_@@_table_int } {#1} {#2}
  }
\cs_new_protected_nopar:Npn \@@_make_table:nnn #1#2#3
  {
    \section{#2~(\zref@extractdefault{#1}{default}{0})}
    \zref@refused{#1}
    \noindent
    \begin{longtabu} to \linewidth {>{\ttfamily\footnotesize}rc>{\ttfamily\footnotesize}X>{\tiny}X}
      \toprule\rowfont{\normalfont\normalsize}
      \multicolumn1c{USV} & Symbol & Macro(s) & Description \\
      \midrule \endhead
      \bottomrule \endfoot
      \int_gzero:N \g_@@_symbol_int
      \input{#3}
    \end{longtabu}
    \group_begin:
      \zref@setcurrent{default}{\int_use:N\g_@@_symbol_int}
      \zref@wrapper@immediate{\zref@labelbyprops{#1}{default}}
    \group_end:
  }
\cs_generate_variant:Nn \@@_make_table:nnn { x }
\ExplSyntaxOff

\begin{document}

\UTFTABLE{Symbols}{xunicode-commands.tex}

\UTFTABLE{Combining Marks}{xunicode-combine-marks.tex}

\end{document}
%    \end{macrocode}
%
%    \begin{macrocode}
%</xunicode-symbols>
%    \end{macrocode}
%
% \end{comment}
%
% \end{implementation}
%
%
% \Finale
%
\endinput
