<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">% \iffalse meta-comment
% !TEX program  = XeLaTeX
%&lt;*internal&gt;
\iffalse
%&lt;/internal&gt;
%&lt;*readme&gt;
xpinyin
=======

`xpinyin` is a LaTeX package written to simplify the input of Hanyu Pinyin.
The package provides macros to automatically add pinyin to Chinese characters.
It can only be used in conjunction with `xeCJK` or `CJK/CJKutf8` package.

Given that the implementation of pinyin package of `CJK` bundle is not very
well, it seems that xpinyin is a good replacement of it.

You can read the package manual (in Chinese) for more detailed explanations.

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

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

Issues and pull requests are welcome.

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

    Copyright (C) 2012-2022 by Qing Lee &lt;sobenlee@gmail.com&gt;
    ----------------------------------------------------------------------

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

    This work has the LPPL maintenance status "maintained".

    The Current Maintainer of this work is Qing Lee.

    This package consists of the file  xpinyin.dtx,
                 and the derived files xpinyin.sty,
                                       xpinyin.pdf,
                                       xpinyin.ins,
                                       xpinyin.lua,
                                       xpinyin.db,
                                       xpinyin-database.def and
                                       README.md (this file).

%&lt;/readme&gt;
%&lt;*internal&gt;
\fi
\begingroup
  \def\temp{LaTeX2e}
\expandafter\endgroup\ifx\temp\fmtname\else
\csname fi\endcsname
%&lt;/internal&gt;
%&lt;*install&gt;

%&lt;install&gt;\begingroup\expandafter\expandafter\expandafter\endgroup
%&lt;install&gt;\expandafter\ifx\csname directlua\endcsname\relax
%&lt;install&gt;  \begingroup
%&lt;install&gt;  \newlinechar=10 %
%&lt;install&gt;  \errmessage{^^J
%&lt;install&gt;    ********************************************^^J
%&lt;install&gt;    * LuaTeX is required to unpack this package.^^J
%&lt;install&gt;    ********************************************^^J
%&lt;install&gt;  }
%&lt;install&gt;  \endgroup
%&lt;install&gt;  \csname @@end\expandafter\endcsname\expandafter\end
%&lt;install&gt;\fi

\input ctxdocstrip %

\let\MetaPrefix\relax

\preamble

    Copyright (C) 2012-2022 by Qing Lee &lt;sobenlee@gmail.com&gt;
--------------------------------------------------------------------------

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

    This work has the LPPL maintenance status "maintained".

    The Current Maintainer of this work is Qing Lee.

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

\endpreamble

\postamble

    This package consists of the file  xpinyin.dtx,
                 and the derived files xpinyin.sty,
                                       xpinyin.pdf,
                                       xpinyin.ins,
                                       xpinyin.lua,
                                       xpinyin.db,
                                       xpinyin-database.def and
                                       README.md.
\endpostamble

\declarepostamble\emptypostamble
\endpostamble

\def\MetaPrefix{-- }

\generate
  {
    \usedir{source/latex/xpinyin}
    \usepostamble\emptypostamble
    \file{xpinyin.lua} {\from{\jobname.dtx}{lua}}
  }

\let\MetaPrefix\DoubleperCent

%&lt;install&gt;\directlua
%&lt;install&gt;  {
%&lt;install&gt;    if not kpse.find_file("xpinyin.db") then
%&lt;install&gt;      dofile(kpse.find_file("xpinyin.lua"))
%&lt;install&gt;    end
%&lt;install&gt;  }
%&lt;install&gt;\generate
%&lt;install&gt;  {
%&lt;install&gt;    \usedir{tex/latex/xpinyin}
%&lt;install&gt;    \usepostamble\emptypostamble
%&lt;install&gt;    \file{xpinyin-database.def}
%&lt;install&gt;      {
%&lt;install&gt;        \from{\jobname.dtx} {database}
%&lt;install&gt;        \from{xpinyin.db}   {}
%&lt;install&gt;      }
%&lt;install&gt;  }

\generate
  {
%&lt;/install&gt;
%&lt;*internal&gt;
    \usedir{source/latex/xpinyin}
    \file{xpinyin.ins} {\from{\jobname.dtx}{install}}
%&lt;/internal&gt;
%&lt;*install&gt;
    \usedir{tex/latex/xpinyin}
    \file{xpinyin.sty} {\from{\jobname.dtx}{package}}
    \nopreamble\nopostamble
    \usedir{doc/latex/xpinyin}
    \file{README.md}   {\from{\jobname.dtx}{readme}}
  }

\endbatchfile
%&lt;/install&gt;
%&lt;*internal&gt;
\fi
%&lt;/internal&gt;
%&lt;package&gt;\NeedsTeXFormat{LaTeX2e}
%&lt;package&gt;\RequirePackage{expl3}
%&lt;+package&gt;\GetIdInfo$Id: xpinyin.dtx dd0cc20 2022-07-14 18:53:49 +0800 Qing Lee &lt;sobenlee@gmail.com&gt; $
%&lt;package&gt;  {Automatically add pinyin to Chinese characters}
%&lt;package&gt;\ProvidesExplPackage{\ExplFileName}
%&lt;package&gt;  {\ExplFileDate}{3.1}{\ExplFileDescription}
%&lt;database&gt;\ProvidesFile{xpinyin-database.def}%
%&lt;database&gt;  [2022/07/14 v3.1 xpinyin database]
%&lt;*driver&gt;
\documentclass{ctxdoc}
\usepackage{xpinyin}
\newfontfamily\PinYinFont{TeX Gyre Adventor}
\xpinyinsetup{font=\PinYinFont,multiple=\color{red}}
\begin{document}
  \DocInput{\jobname.dtx}
  \IndexLayout
  \PrintIndex
\end{document}
%&lt;/driver&gt;
% \fi
%
% \CheckSum{695}
% \GetFileId{xpinyin.sty}
%
% \title{\bfseries\pkg{xpinyin} å®åŒ…}
% \author{æŽæ¸…\\ \path{sobenlee@gmail.com}}
% \date{\filedate\qquad\fileversion\thanks{\ctexkitrev{\ExplFileVersion}.}}
% \maketitle
%
% \begin{documentation}
%
% \section{ç®€ä»‹}
%
% \pkg{xpinyin} æ˜¯ä¸€ä¸ª \LaTeX å®åŒ…ï¼Œæä¾›äº†ä¸ºæ±‰å­—è‡ªåŠ¨æ³¨éŸ³çš„åŠŸèƒ½ã€‚
%
% \section{åŸºæœ¬ç”¨æ³•}
%
% \pkg{xpinyin} æ”¯æŒé‡‡ç”¨ \texttt{GBK} å’Œ \texttt{UTF-8} ç¼–ç&nbsp;çš„ \TeX æºæ–‡ä»¶ï¼Œå»ºè®®
% æ€»æ˜¯ä½¿ç”¨ \texttt{UTF-8}ã€‚å¦‚æžœä½¿ç”¨ \LaTeX æˆ– \pdfLaTeX\ çš„ç¼–è¯‘æ–¹å¼ï¼Œåˆ™æ&nbsp;¹æ®ç¼–ç&nbsp;çš„
% æƒ…å†µï¼Œ\pkg{xpinyin} ä¾èµ– \package{CJK} æˆ–è€… \package[cjk]{CJKutf8} å®åŒ…ã€‚
% å¦‚æžœä½¿ç”¨ \XeLaTeXï¼Œåˆ™ä¾èµ– \package{xeCJK} å®åŒ…ã€‚å¦‚æžœå®ƒä»¬æ²¡æœ‰åœ¨ \pkg{xpinyin}
% ä¹‹å‰è¢«è½½å…¥ï¼Œ\pkg{xpinyin} å°†æ&nbsp;¹æ®ç¼–è¯‘æ–¹å¼è‡ªåŠ¨é€‰æ‹©ï¼Œ\LaTeX æˆ– \pdfLaTeX\ å°†ä½¿ç”¨
% \pkg{CJKutf8}ã€‚
%
% \pkg{xpinyin} è¿˜ä¾èµ– \package{l3kernel} å’Œ \package{l3packages}ï¼Œä½¿ç”¨ (pdf)\LaTeX
% ä¸‹çš„ \texttt{GBK} ç¼–ç&nbsp;æ—¶ï¼Œè¿˜å°†ä¾èµ– \package{xCJK2uni}ã€‚
%
% éœ€è¦æ³¨æ„çš„æ˜¯ï¼Œ\pkg{xpinyin} ç¼ºçœå°†æ‹¼éŸ³çš„å­—ä½“è®¾ç½®ä¸ºä¸Žæ–‡æ¡£çš„ä¸»å­—ä½“ï¼ˆ\tn{normalfont}ï¼‰ç›¸åŒï¼Œ
% æ‰€ä»¥ä¸ºäº†ä¿è¯å£°è°ƒå­—æ¯çš„æ­£ç¡®è¾“å‡ºï¼Œåº”è¯¥é€‰ç”¨åˆé€‚çš„è¥¿æ–‡ä¸»å­—ä½“ã€‚ä¹Ÿå¯ä»¥é€šè¿‡å°†åœ¨ä¸‹ä¸€èŠ‚ä»‹ç»çš„
% \meta{font} é€‰é¡¹æ¥å•ç‹¬è®¾ç½®æ‹¼éŸ³çš„å­—ä½“ã€‚
%
% \begin{minipage}[t]{\dimexpr(\linewidth-\parindent-2em)/2\relax}
% \XeLaTeX ä¸‹çš„ç®€å•ç¤ºä¾‹ï¼š
% \begin{verbatim}[frame=single,gobble=3]
%   \documentclass{article}
%   \usepackage{xeCJK}
%   \usepackage{xpinyin}
%   \setmainfont{CMU Serif}
%   \setCJKmainfont{SimSun}
%
%   \begin{document}
%   \xpinyin*{æ±‰è¯­æ‹¼éŸ³ç¤ºä¾‹}
%   \end{document}
% \end{verbatim}
% \end{minipage}\qquad
% \begin{minipage}[t]{\dimexpr(\linewidth-\parindent-2em)/2\relax}
% (pdf)\LaTeX ä¸‹çš„ç®€å•ç¤ºä¾‹ï¼š
% \begin{verbatim}[frame=single,gobble=3]
%   \documentclass{article}
%   \usepackage{CJKutf8}
%   \usepackage{xpinyin}
%   \usepackage[T1]{fontenc}
%   \usepackage{lmodern}
%
%   \begin{document}
%   \begin{CJK}{UTF8}{gbsn}
%   \xpinyin*{æ±‰è¯­æ‹¼éŸ³ç¤ºä¾‹}
%   \end{CJK}
%   \end{document}
% \end{verbatim}
% \hrule height \dp\strutbox width 0pt \relax
% \end{minipage}
%
% è¿è¡Œä¸Šè¿°ç¤ºä¾‹è¦æ±‚ç³»ç»Ÿå®‰è£…äº†è®¾ç½®çš„å­—ä½“ï¼Œæºæ–‡ä»¶ç”¨ |UTF-8| ç¼–ç&nbsp;ä¿å­˜ï¼Œä½¿ç”¨ç›¸åº”çš„ç¼–è¯‘æ–¹å¼ã€‚
%
% \pkg{xpinyin} å¯ä»¥ä¸Ž \package{ctex} å®åŒ…æˆ–æ–‡æ¡£ç±»å…±åŒä½¿ç”¨ï¼Œä½¿ç”¨æ–¹å¼ä¸Žä¸Šé¢ç±»ä¼¼ã€‚
%
% \section{ç”¨æˆ·æ‰‹å†Œ}
%
% \begin{function}{pinyinscope}
%   \begin{syntax}
%     \tn{begin}\{pinyinscope\}\oarg{options}
%     .....
%     \tn{end}\{pinyinscope\}
%   \end{syntax}
%   ä¸º \env{pinyinscope} çŽ¯å¢ƒä¸­çš„æ±‰å­—è‡ªåŠ¨æ³¨éŸ³ã€‚ä¾‹å¦‚
%   \begin{Example}[frame=single,numbers=left,gobble=5]
%     \begin{pinyinscope}
%     åˆ—ä½çœ‹å®˜ï¼šä½&nbsp;é“æ­¤ä¹¦ä»Žä½•è€Œæ¥ï¼Ÿè¯´èµ·æ&nbsp;¹ç”±ï¼Œè™½è¿‘è’å”ï¼Œç»†æŒ‰åˆ™æ·±æœ‰è¶£å‘³ã€‚
%     å¾…åœ¨ä¸‹å°†æ­¤æ¥åŽ†æ³¨æ˜Žï¼Œæ–¹ä½¿é˜…è€…\xpinyin{äº†}{liao3}ç„¶ä¸æƒ‘ã€‚
%     \end{pinyinscope}
%   \end{Example}
% \end{function}
%
%   å¯é€‰é¡¹ \meta{options} ç”¨äºŽå±€éƒ¨è®¾ç½®æ‹¼éŸ³çš„æ&nbsp;¼å¼ï¼Œå°†åœ¨ä¸‹é¢è¯´æ˜Žã€‚
%
% \begin{function}{\xpinyin}
%   \begin{syntax}
%     \tn{xpinyin} \oarg{options} \Arg{å•ä¸ªæ±‰å­—} \Arg{æ‹¼éŸ³}
%     \tn{xpinyin*} \oarg{options} \Arg{æ–‡å­—}
%   \end{syntax}
%   å¯¹äºŽå¤šéŸ³å­—ï¼Œå¯ä»¥ä½¿ç”¨ \tn{xpinyin} ä¸ºå…¶è®¾ç½®æ‹¼éŸ³ï¼›è€Œ \tn{xpinyin*} ç›¸å½“äºŽ
%   \env{pinyinscope} çŽ¯å¢ƒçš„å‘½ä»¤å½¢å¼ã€‚\tn{xpinyin} å¯ä»¥åœ¨ \env{pinyinscope} çŽ¯å¢ƒå’Œ
%   \tn{xpinyin*} ä¸­ä½¿ç”¨ã€‚ä¾‹å¦‚ï¼Œ
%   \begin{SideBySideExample}
%     \xpinyin{é•¿}{chang2}\\
%     \xpinyin*{ç”„å£«éšæ¢¦å¹»è¯†é€šçµ}\\
%     \xpinyin*{\xpinyin{é‡}{zhong4}è¦}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}{\pinyin}
%   \begin{syntax}
%     \tn{pinyin} \oarg{options} \Arg{æ‹¼éŸ³}
%   \end{syntax}
%   ç”¨äºŽè¾“å‡ºæ‹¼éŸ³ï¼Œä¸ºäº†è¾“å…¥çš„æ–¹ä¾¿ \texttt{\"u} å¯ä»¥ç”¨ |v| ä»£æ›¿ã€‚ä¾‹å¦‚ï¼Œ
%   \begin{SideBySideExample}
%     \pinyin{lv2zi}\\
%     \pinyin{nv3hai2zi}
%   \end{SideBySideExample}
% \end{function}
%
% \begin{function}{\setpinyin}
%   \begin{syntax}
%     \tn{setpinyin} \Arg{æ±‰å­—} \Arg{æ‹¼éŸ³}
%   \end{syntax}
%   \pkg{xpinyin} å®åŒ…çš„æ‹¼éŸ³æ•°æ®ï¼ˆ\file{xpinyin-database.def}ï¼‰æ¥æºäºŽ \texttt{Unicode}
%   çš„ \texttt{Unihan} æ•°æ®åº“\footnotemark ä¸­çš„ \file{Unihan_Readings.txt} æ–‡ä»¶ã€‚å¯¹äºŽå¤š
%   éŸ³å­—ï¼Œä¸€èˆ¬æ¥è¯´è¿™ä¸ªæ–‡ä»¶é€‰ç”¨çš„æ˜¯å¸¸ç”¨è¯»éŸ³ã€‚å¯ä»¥ä½¿ç”¨ \tn{setpinyin} æ¥è®¾ç½®å¤šéŸ³å­—çš„é¦–é€‰è¯»éŸ³ã€‚
% \end{function}
%
% \footnotetext{\url{http://www.unicode.org/Public/UNIDATA/Unihan.zip}}
%
% \begin{function}{\xpinyinsetup}
%   \begin{syntax}
%     \tn{xpinyinsetup} \{ &lt;key_1&gt;=&lt;val_1&gt;, &lt;key_2&gt;=&lt;val_2&gt;, ... \}
%   \end{syntax}
%   ç”¨äºŽåœ¨å¯¼è¨€åŒºæˆ–æ–‡æ¡£ä¸­ï¼Œè®¾ç½®æ‹¼éŸ³çš„æ&nbsp;¼å¼ã€‚ç›®å‰å¯ä»¥è®¾ç½®çš„ \meta{key} å¦‚ä¸‹ä»‹ç»ã€‚
% \end{function}
%
% \begin{function}{ratio}
%   \begin{syntax}
%     ratio = \Arg{number}
%   \end{syntax}
%   è®¾ç½®æ‹¼éŸ³å­—ä½“å¤§å°ä¸Žå½“å‰æ­£æ–‡å­—ä½“å¤§å°çš„æ¯”ä¾‹ï¼Œç¼ºçœå€¼æ˜¯ |0.4|ã€‚
% \end{function}
%
% \begin{function}{vsep}
%   \begin{syntax}
%     vsep = \Arg{dimen}
%   \end{syntax}
%   è®¾ç½®æ‹¼éŸ³çš„åŸºçº¿ä¸Žæ±‰å­—åŸºçº¿çš„é—´è·ï¼Œç¼ºçœå€¼æ˜¯ |1 em|ã€‚
% \end{function}
%
% \begin{function}{hsep}
%   \begin{syntax}
%     hsep = \Arg{skip}
%   \end{syntax}
%   è®¾ç½®æ³¨éŸ³æ±‰å­—ä¹‹é—´çš„é—´è·ï¼Œç¼ºçœå€¼ä¸Ž \tn{CJKglue} çš„å€¼ç›¸åŒã€‚ä¸ºäº†æ–­è¡Œæ—¶è¡Œæœ«çš„å¯¹é½ï¼Œè®¾ç½®
%   çš„ \meta{skip} æœ€åŽæœ‰ä¸€å®šçš„å¼¹æ€§ã€‚ä¾‹å¦‚
%   \begin{Example}[frame=single,numbers=left,gobble=5]
%     \xpinyin*[ratio={.7},hsep={.5em plus .1em},vsep={1.1em}]{è´¾é›¨æ‘é£Žå°˜æ€€é—ºç§€}
%   \end{Example}
% \end{function}
%
% \begin{function}{pysep}
%   \begin{syntax}
%     pysep = \Arg{glue}
%   \end{syntax}
%   è®¾ç½® \tn{pinyin} è¾“å‡ºçš„ç›¸é‚»ä¸¤ä¸ªæ±‰è¯­æ‹¼éŸ³çš„ç©ºç™½ï¼Œç¼ºçœå€¼æ˜¯ä¸€ä¸ªç©ºæ&nbsp;¼ã€‚
% \end{function}
%
% \begin{function}{font}
%   \begin{syntax}
%     font = \Arg{font}
%   \end{syntax}
%   è®¾ç½®æ‹¼éŸ³çš„å­—ä½“ï¼Œç¼ºçœå€¼æ˜¯ \tn{normalfont}ï¼Œå³ä»¥æ­£æ–‡è¥¿æ–‡å­—ä½“ç›¸åŒã€‚ä¸ºäº†ä¿è¯æ‹¼éŸ³èƒ½æ­£ç¡®
%   è¾“å‡ºï¼Œæœ€å¥½é€‰ç”¨æ”¶å­—é‡è¾ƒå¤§çš„è¥¿æ–‡å­—ä½“ã€‚
% \end{function}
%
% \begin{function}{format}
%   \begin{syntax}
%     format = \Arg{format}
%   \end{syntax}
%   è®¾ç½®æ‹¼éŸ³çš„å…¶ä»–æ&nbsp;¼å¼ï¼Œä¾‹å¦‚é¢œè‰²ç­‰ï¼Œç¼ºçœå€¼ä¸ºç©ºã€‚
% \end{function}
%
% \begin{function}{multiple}
%   \begin{syntax}
%     multiple = \Arg{format}
%   \end{syntax}
%   è®¾ç½®å¤šéŸ³å­—æ‹¼éŸ³çš„å…¶ä»–æ&nbsp;¼å¼ï¼Œç¼ºçœå€¼ä¸ºç©ºã€‚å¯ä»¥é€šè¿‡è¿™ä¸ªé€‰é¡¹æ¥æé†’æ&nbsp;¡æ­£å¤šéŸ³å­—çš„æ‹¼éŸ³ã€‚
%   æ³¨æ„è¿™ä¸ªé€‰é¡¹ä¼šè¦†ç›– \opt{format} è®¾ç½®çš„æ&nbsp;¼å¼ã€‚ä¾‹å¦‚æœ¬æ–‡æ¡£è®¾ç½®å¤šéŸ³å­—æ‹¼éŸ³çš„é¢œè‰²æ˜¯
%   çº¢è‰²ï¼ˆéœ€è¦è½½å…¥ \pkg{color} å®åŒ…ï¼‰ï¼š
%   \begin{frameverb}
%   \xpinyinsetup{multiple={\color{red}}}
%   \end{frameverb}
% \end{function}
%
% \begin{function}[added=2014/01/12]{footnote}
%   \begin{syntax}
%     footnote = &lt;\TFF&gt;
%   \end{syntax}
%   æ˜¯å¦å¯¹æ‹¼éŸ³çŽ¯å¢ƒä¸­çš„è„šæ³¨ï¼ˆ\tn{footnote}ï¼‰æ±‰å­—åŠ&nbsp;ä¸Šæ‹¼éŸ³ã€‚ç¼ºçœå€¼ä¸º \texttt{false}ã€‚
%   æ›´ä¸€èˆ¬çš„æƒ…å†µï¼Œè¯·ä½¿ç”¨ \tn{disablepinyin}ã€‚
% \end{function}
%
% \begin{function}[added=2014/01/12]{\disablepinyin,\enablepinyin}
%   \tn{disablepinyin} ç”¨äºŽåœ¨æ‹¼éŸ³çŽ¯å¢ƒï¼ˆ\env{pinyinscope}ï¼‰ä¸­ä¸´æ—¶å–æ¶ˆå¯¹æ±‰å­—çš„æ³¨éŸ³ï¼Œè€Œ
%   \tn{enablepinyin} ç”¨äºŽå…¶åŽçš„æ¢å¤ã€‚
% \end{function}
%
% \end{documentation}
%
% \StopEventually{}
%
% \begin{implementation}
%
% \section{ä»£ç&nbsp;å®žçŽ°}
%
%    \begin{macrocode}
%&lt;*package&gt;
%&lt;@@=xpinyin&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
\msg_new:nnn { xpinyin } { l3-too-old }
  {
    Support~package~'expl3'~too~old. \\\\
    Please~update~an~up~to~date~version~of~the~bundles\\\\
    'l3kernel'~and~'l3packages'\\\\
    using~your~TeX~package~manager~or~from~CTAN.
  }
\@ifpackagelater { expl3 } { 2019/03/05 } { }
  { \msg_error:nn { xpinyin } { l3-too-old } }
%    \end{macrocode}
%
%    \begin{macrocode}
\msg_new:nnn { xpinyin } { engine-not-supported }
  { Engine~`\c_sys_engine_str'~is~not~yet~supported,~xpinyin~will~abort! }
\bool_lazy_or:nnF
  { \sys_if_engine_xetex_p: }
  { \sys_if_engine_pdftex_p: }
  { \msg_critical:nn { xpinyin } { engine-not-supported } }
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_if_exist:NF \NewDocumentCommand
  { \RequirePackage { xparse } }
%    \end{macrocode}
%
% \begin{variable}{\c_@@_tone_prop}
% é‡éŸ³æ&nbsp;‡è®° |\`|ã€|\'| å’Œ |\=| åœ¨ \env{tabbing} çŽ¯å¢ƒä¸­è¢«ç§»ä½œä»–ç”¨ï¼Œä¸ºé¿å…é”™è¯¯ï¼Œ
% æˆ‘ä»¬ä½¿ç”¨å†…éƒ¨å‘½ä»¤ \tn{@tabacckludge} æˆ– \tn{a} æ¥å®šä¹‰ã€‚
%    \begin{macrocode}
\prop_const_from_keyval:Nn \c_@@_tone_prop
  {
    { Ä } = { \@tabacckludge= a } ,
    { Ã¡ } = { \@tabacckludge' a } ,
    { ÇŽ } = { \v a } ,
    { Ã&nbsp; } = { \@tabacckludge` a } ,
    { Å } = { \@tabacckludge= o } ,
    { Ã³ } = { \@tabacckludge' o } ,
    { Ç’ } = { \v o } ,
    { Ã² } = { \@tabacckludge` o } ,
    { Ä“ } = { \@tabacckludge= e } ,
    { Ã© } = { \@tabacckludge' e } ,
    { Ä› } = { \v e } ,
    { Ã¨ } = { \@tabacckludge` e } ,
    { Å« } = { \@tabacckludge= u } ,
    { Ãº } = { \@tabacckludge' u } ,
    { Ç” } = { \v u } ,
    { Ã¹ } = { \@tabacckludge` u } ,
    { á¸¿ } = { \@tabacckludge' m } ,
    { Å„ } = { \@tabacckludge' n } ,
    { Åˆ } = { \v n } ,
    { Ç¹ } = { \@tabacckludge` n } ,
    { Ä« } = { \@tabacckludge= { \i } } ,
    { Ã­ } = { \@tabacckludge' { \i } } ,
    { Ç } = { \v { \i } } ,
    { Ã¬ } = { \@tabacckludge` { \i } } ,
    { Ã¼ } = { \" u } ,
    { Ç– } = { \@tabacckludge= { \" u } } ,
    { Ç˜ } = { \@tabacckludge' { \" u } } ,
    { Çš } = { \v { \" u } } ,
    { Çœ } = { \@tabacckludge` { \" u } }
  }
%    \end{macrocode}
% \end{variable}
%
%
% \begin{macro}{\@@_UTF_char:nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_UTF_char:nn #1#2
  {
    \cs_if_exist:cF { u8:#1 }
      { \tl_const:cn { u8:#1 } {#2} }
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_GBK_char:nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_GBK_char:nn #1#2
  {
    \@@_UTF_char:nn {#1} {#2}
    \exp_args:Nx \@@_GBK_char_aux:nn { \tl_head:n {#1} } {#1}
  }
\cs_new_protected:Npn \@@_GBK_char_aux:nn #1#2
  { \exp_args:Nf \@@_GBK_char_aux:nnn { \int_eval:n { `#1 } } {#1} {#2} }
\cs_new_protected:Npn \@@_GBK_char_aux:nnn #1#2#3
  {
    \cs_if_exist:cF { @@_UTF_ #1 :w }
      {
        \exp_args:Nf \@@_GBK_char_def:nnn
          {
            \int_case:nn { \tl_count:n {#3} }
              {
                { 2 } { ##1 }
                { 3 } { ##1##2 }
                { 4 } { ##1##2##3 }
              }
          }
          {#1} {#2}
        \exp_args:Nc \@@_save_UTF_cs:Nn { @@_UTF_ #1 :w } {#1}
        \tl_gput_right:Nx \c_@@_reset_UTF_catcode_tl
          { \char_set_catcode:nn {#1} { \char_value_catcode:n {#1} } }
        \char_set_catcode_active:n {#1}
      }
  }
\cs_new_protected:Npn \@@_GBK_char_def:nnn #1#2#3
  {
    \cs_new_protected:cpn { @@_UTF_ #2 :w } #1
      { \use:c { u8: \tl_to_str:n { #3#1 } } }
  }
\tl_new:N \c_@@_reset_UTF_catcode_tl
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_save_UTF_cs:Nn}
%    \begin{macrocode}
\group_begin:
\char_set_catcode_active:n { 126 }
\cs_new_protected:Npn \@@_save_UTF_cs:Nn #1#2
  {
    \group_begin:
    \char_set_lccode:nn { 126 } {#2}
    \tex_lowercase:D
      {
        \group_end:
        \tl_gput_right:Nn \c_@@_reset_UTF_cs_tl { \cs_set_eq:NN ~ #1 }
      }
  }
\group_end:
\tl_new:N \c_@@_reset_UTF_cs_tl
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\bool_new:N \g_@@_GBK_bool
\@ifpackageloaded { xeCJK }
  { \AtEndOfPackage { \@@_adjust_xeCJK_hook: } }
  {
    \@ifpackageloaded { CJKutf8 }
      {
        \prop_map_function:NN \c_@@_tone_prop \@@_UTF_char:nn
        \AtEndOfPackage { \@@_adjust_CJK_hook: }
      }
      {
        \@ifpackageloaded { CJK }
          {
            \RequirePackage { xCJK2uni }
            \prop_map_function:NN \c_@@_tone_prop \@@_GBK_char:nn
            \AtEndOfPackage
              {
                \tl_put_right:Nn \l_@@_pinyin_box_hook_tl
                  { \c_@@_reset_UTF_cs_tl }
                \@@_adjust_CJK_hook:
                \tl_use:N \c_@@_reset_UTF_catcode_tl
              }
            \bool_gset_true:N \g_@@_GBK_bool
          }
          {
            \sys_if_engine_xetex:TF
              {
                \RequirePackage { xeCJK }
                \AtEndOfPackage { \@@_adjust_xeCJK_hook: }
              }
              {
                \RequirePackage { CJKutf8 }
                \prop_map_function:NN \c_@@_tone_prop \@@_UTF_char:nn
                \AtEndOfPackage { \@@_adjust_CJK_hook: }
              }
          }
      }
  }
%    \end{macrocode}
%
% \begin{variable}{\l_@@_tmpa_box,\l_@@_tmpb_box}
%    \begin{macrocode}
\box_new:N \l_@@_tmpa_box
\box_new:N \l_@@_tmpb_box
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_width:Nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_width:Nn #1#2
  {
    \hbox_set:Nn \l_@@_tmpa_box {#2}
    #1 = \box_wd:N \l_@@_tmpa_box
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_make_pinyin_box:nnn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_make_pinyin_box:nnn #1#2#3
  {
    \@@_leavevmode:
    \hbox_overlap_right:n
      {
        \hbox_set:Nn \l_@@_tmpa_box
          { \@@_CJKsymbol_hook: \@@_save_CJKsymbol:n {#2} }
        \hbox_set:Nn \l_@@_tmpb_box
          {
            \l_@@_pinyin_box_hook_tl
            \@@_select_font:
            \l_@@_format_tl
            \clist_if_exist:cT { c_@@_multiple_ #1 _clist }
              { \l_@@_multiple_tl }
            {#3}
          }
        \dim_compare:nNnT
          { \box_wd:N \l_@@_tmpb_box } &gt;
          { \box_wd:N \l_@@_tmpa_box + \l_@@_CJKglue_dim }
          {
            \box_resize_to_wd_and_ht:Nnn \l_@@_tmpb_box
              { \box_wd:N \l_@@_tmpa_box + \l_@@_CJKglue_dim }
              { \box_ht:N \l_@@_tmpb_box }
          }
        \box_move_up:nn { \l_@@_vsep_tl }
          {
            \hbox_to_wd:nn { \box_wd:N \l_@@_tmpa_box }
              { \tex_hss:D \box_use_drop:N \l_@@_tmpb_box \tex_hss:D }
          }
      }
  }
\tl_new:N \l_@@_pinyin_box_hook_tl
\sys_if_engine_pdftex:T
  {
    \tl_put_right:Nn \l_@@_pinyin_box_hook_tl
      { \cs_set_eq:NN \CJK@plane \tex_undefined:D }
  }
\cs_generate_variant:Nn \@@_make_pinyin_box:nnn { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_CJKsymbol:n}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_CJKsymbol:n #1
  { \@@_CJKsymbol:xn { \@@_to_unicode:n {#1} } {#1} }
\cs_new_protected:Npn \@@_CJKsymbol:nn #1#2
  {
    \@@_make_pinyin_box:nnn {#1} {#2} { \use:c { c_@@_ #1 _tl } }
    \@@_save_CJKsymbol:n {#2}
  }
\cs_generate_variant:Nn \@@_CJKsymbol:nn { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{pinyinscope}
%    \begin{macrocode}
\NewDocumentEnvironment { pinyinscope } { O { } }
  {
    \keys_set:nn { xpinyin } {#1}
    \enablepinyin
  }
  { }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xpinyin}
%    \begin{macrocode}
\NewDocumentCommand \xpinyin { s O { } m }
  {
    \mode_leave_vertical:
    \IfBooleanTF {#1}
      {
        \group_begin:
          \keys_set:nn { xpinyin } {#2}
          \enablepinyin
          #3
        \group_end:
      }
      {
        \group_begin:
          \keys_set:nn { xpinyin } {#2}
          \bool_if:NF \l_@@_enable_bool
            { \@@_width:Nn \l_@@_CJKglue_dim { \CJKglue } }
          \@@_single_aux:nn {#3}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_enable_bool}
%    \begin{macrocode}
\bool_new:N \l_@@_enable_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_CJKglue:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_CJKglue:
  { \skip_horizontal:n { \l_@@_hsep_tl } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\enablepinyin}
%    \begin{macrocode}
\NewDocumentCommand \enablepinyin { }
  {
    \bool_if:NF \l_@@_enable_bool
      {
        \tl_if_empty:NF \l_@@_hsep_tl
          {
            \cs_set_eq:NN \@@_save_CJKglue: \CJKglue
            \cs_set_eq:NN \CJKglue \@@_CJKglue:
          }
        \@@_width:Nn \l_@@_CJKglue_dim { \CJKglue }
        \@@_replace_CJKsymbol:
        \@@_restore_footnote:
        \bool_set_true:N \l_@@_enable_bool
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\disablepinyin}
%    \begin{macrocode}
\NewDocumentCommand \disablepinyin { }
  {
    \bool_if:NT \l_@@_enable_bool
      {
        \cs_if_eq:NNT \CJKglue \@@_CJKglue:
          { \cs_set_eq:NN \CJKglue \@@_save_CJKglue: }
        \@@_restore_CJKsymbol:
        \bool_set_false:N \l_@@_enable_bool
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_restore_footnote:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_restore_footnote:
  {
    \bool_if:NF \l_@@_footnote_bool
      { \tl_put_left:Nn \@parboxrestore { \l_@@_restore_footnote_tl } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_restore_footnote_tl}
%    \begin{macrocode}
\tl_new:N \l_@@_restore_footnote_tl
\tl_set:Nn \l_@@_restore_footnote_tl
  {
    \int_compare:nNnT \tex_currentgrouptype:D = { 11 }
      { \disablepinyin }
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_CJKglue_dim}
%    \begin{macrocode}
\dim_new:N \l_@@_CJKglue_dim
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_single_aux:nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_single_aux:nn #1#2
  {
      \@@_replace_CJKsymbol_single:n {#2}
      #1
    \group_end:
  }
\cs_new_protected:Npn \@@_replace_CJKsymbol_single_aux:n #1
  {
    \bool_if:NF \l_@@_enable_bool { \@@_replace_CJKsymbol: }
    \cs_set_protected:Npn \CJKsymbol ##1
      { \@@_single_CJKsymbol:nn {##1} {#1} }
  }
\cs_new_protected:Npn \@@_single_CJKsymbol:nn #1#2
  {
    \@@_make_pinyin_box:xnn
      { \@@_to_unicode:n {#1} } {#1} { \@@_pinyin:n {#2} }
    \@@_save_CJKsymbol:n {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_replace_CJKsymbol_aux:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_replace_CJKsymbol_aux:
  {
    \cs_set_eq:NN \@@_save_CJKsymbol:n \CJKsymbol
    \cs_set_eq:NN \CJKsymbol \@@_CJKsymbol:n
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_restore_CJKsymbol_aux:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_restore_CJKsymbol_aux:
  { \cs_set_eq:NN \CJKsymbol \@@_save_CJKsymbol:n }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_select_font_xetex:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_select_font_xetex:
  {
    \cs_if_exist_use:cF { \l_@@_coor_tl }
      {
        \tl_set:Nx \l_@@_current_coor_tl { \l_@@_coor_tl }
        \@@_select_font_aux:
        \int_compare:nNnF { \tex_XeTeXfonttype:D \tex_font:D } = \c_zero_int
          {
            \exp_last_unbraced:NNV
            \cs_gset_eq:cN \l_@@_current_coor_tl \tex_font:D
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_select_font_aux:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_select_font_aux:
  {
    \fontsize
      { \l_@@_ratio_tl \tex_dimexpr:D \f@size pt \scan_stop: }
      { \f@baselineskip }
    \normalfont
    \l_@@_font_tl
    \selectfont
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_to_unicode_xetex:n}
%    \begin{macrocode}
\cs_new:Npn \@@_to_unicode_xetex:n #1
  { \int_to_arabic:n { `#1 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_UTF_to_unicode:n,\@@_UTFchar_to_unicode:n}
%    \begin{macrocode}
\cs_new:Npn \@@_UTF_to_unicode:n #1
  {
    \int_to_arabic:n
      { \exp_args:No \int_from_hex:n { \CJK@plane } * "100 + #1 }
  }
\cs_new:Npn \@@_UTFchar_to_unicode:n #1
  { \int_to_arabic:n { \@@_UTF_viii_to_unicode:NNNw #1 \q_stop } }
\cs_new:Npn \@@_UTF_viii_to_unicode:NNNw #1#2#3#4 \q_stop
  {
    \tl_if_empty:nTF {#4}
      { ( `#1 - "E0 ) * "1000 + ( `#2 - "80 ) * "40 + ( `#3 - "80 ) }
      { ( `#1 - "F0 ) * "4000 + ( `#2 - "80 ) * "1000 + ( `#3 - "80 ) * "40 + ( `#4 - "80 ) }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_GBK_to_unicode:n,\@@_GBKchar_to_unicode:n}
%    \begin{macrocode}
\cs_new:Npn \@@_GBK_to_unicode:n
  { \CJKtu_sfd_map:nn { \CJK@plane } }
\cs_new:Npn \@@_GBKchar_to_unicode:n
  { \CJKtu_char_to_unicode:n }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_adjust_xeCJK_hook:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_adjust_xeCJK_hook:
  {
    \cs_new_eq:NN \@@_select_font:       \@@_select_font_xetex:
    \cs_new_eq:NN \@@_to_unicode:n       \@@_to_unicode_xetex:n
    \cs_new_eq:NN \@@_char_to_unicode:n  \@@_to_unicode:n
    \cs_new_eq:NN \@@_restore_CJKsymbol: \@@_restore_CJKsymbol_aux:
    \cs_new_eq:NN \@@_replace_CJKsymbol: \@@_replace_CJKsymbol_aux:
    \cs_new_eq:NN \@@_replace_CJKsymbol_single:n
                  \@@_replace_CJKsymbol_single_aux:n
    \tl_if_exist:NTF \l_xeCJK_current_font_tl
      {
        \tl_set:Nn \l_@@_coor_tl
          {
            ( \tl_to_str:N \l_@@_font_tl ) /
            \l_xeCJK_current_font_tl/\l_@@_ratio_tl
          }
      }
      {
        \tl_set:Nn \l_@@_coor_tl
          {
            ( \tl_to_str:N \l_@@_font_tl ) /
            \xeCJK@family/\f@series/\f@shape/\f@size/\l_@@_ratio_tl
          }
      }
    \cs_new_eq:NN \@@_leavevmode: \prg_do_nothing:
    \cs_new_protected:Npx \@@_CJKsymbol_hook:
      {
        \exp_not:N \makexeCJKinactive
        \cs_if_exist_use:NF \xeCJK_select_font:
          { \exp_not:N \xeCJK@setfont }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_adjust_CJK_hook:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_adjust_CJK_hook:
  {
    \bool_if:NTF \g_@@_GBK_bool
      {
        \cs_new_eq:NN \@@_to_unicode:n      \@@_GBK_to_unicode:n
        \cs_new_eq:NN \@@_char_to_unicode:n \@@_GBKchar_to_unicode:n
      }
      {
        \cs_new_eq:NN \@@_to_unicode:n      \@@_UTF_to_unicode:n
        \cs_new_eq:NN \@@_char_to_unicode:n \@@_UTFchar_to_unicode:n
      }
    \cs_new_eq:NN \@@_select_font:    \@@_select_font_aux:
    \cs_new_eq:NN \@@_leavevmode:     \mode_leave_vertical:
    \cs_new_eq:NN \@@_CJKsymbol_hook: \prg_do_nothing:
    \@ifpackageloaded { CJKpunct }
      { \@@_adjust_CJKpunct_hook: }
      {
        \cs_new_eq:NN \@@_restore_CJKsymbol: \@@_restore_CJKsymbol_aux:
        \cs_new_eq:NN \@@_replace_CJKsymbol: \@@_replace_CJKsymbol_aux:
        \cs_new_eq:NN \@@_replace_CJKsymbol_single:n
                      \@@_replace_CJKsymbol_single_aux:n
        \AtBeginDocument
          {
            \@ifpackageloaded { CJKpunct }
              {
                \cs_undefine:N \@@_restore_CJKsymbol:
                \cs_undefine:N \@@_replace_CJKsymbol:
                \cs_undefine:N \@@_replace_CJKsymbol_single:n
                \@@_adjust_CJKpunct_hook:
              } { }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_adjust_CJKpunct_hook:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_adjust_CJKpunct_hook:
  {
    \cs_new_protected:Npn \@@_restore_CJKsymbol:
      {
        \int_compare:nNnTF { \CJKpunct@punctstyle } = { \CJKpunct@ps@plain }
          { \@@_restore_CJKsymbol_aux: }
          { \cs_set_eq:NN \CJKosymbol \@@_save_CJKsymbol:n }
      }
    \cs_new_protected:Npn \@@_replace_CJKsymbol:
      {
        \int_compare:nNnTF { \CJKpunct@punctstyle } = { \CJKpunct@ps@plain }
          { \@@_replace_CJKsymbol_aux: }
          {
            \cs_set_eq:NN \@@_save_CJKsymbol:n \CJKosymbol
            \cs_set_eq:NN \CJKosymbol \@@_CJKsymbol:n
          }
      }
    \cs_new_protected:Npn \@@_replace_CJKsymbol_single:n ##1
      {
        \int_compare:nNnTF { \CJKpunct@punctstyle } = { \CJKpunct@ps@plain }
          { \@@_replace_CJKsymbol_single_aux:n { ##1 } }
          {
            \bool_if:NF \l_@@_enable_bool
              { \cs_set_eq:NN \@@_save_CJKsymbol:n \CJKosymbol }
            \cs_set_protected:Npn \CJKosymbol ####1
              { \@@_single_CJKsymbol:nn { ####1 } { ##1 } }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\pinyin}
%    \begin{macrocode}
\NewDocumentCommand \pinyin { O { } m }
  {
    \group_begin:
    \keys_set:nn { xpinyin } {#1}
    \l_@@_font_tl
    \l_@@_format_tl { }
    \selectfont
    \c_@@_reset_UTF_cs_tl
    \@@_pinyin:n {#2}
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_pinyin:n}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_pinyin:n #1
  {
    \@@_pinyin_init:
    \bool_set_true:N \l_@@_first_bool
    \tl_set:Nn \l_@@_save_tl {#1}
    \@@_pinyin_aux:n #1 \q_recursion_tail \q_recursion_stop
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_pinyin_aux:n}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_pinyin_aux:n #1
  {
    \quark_if_recursion_tail_stop_do:nn {#1}
      {
        \bool_if:NTF \l_@@_first_bool { \l_@@_save_tl }
          { \tl_if_empty:NF \l_@@_item_tl { \l_@@_pysep_tl \l_@@_item_tl } }
      }
    \@@_if_number:nTF {#1}
      {
        \bool_if:NTF \l_@@_first_bool
          { \bool_set_false:N \l_@@_first_bool }
          { \l_@@_pysep_tl }
        \l_@@_pre_tl
        \@@_tone:Vn \l_@@_tone_tl {#1}
        \l_@@_post_tl
        \@@_pinyin_init:
      }
      {
        \int_compare:nNnTF
          { 0 \cs_if_exist_use:c { c_@@_ \tl_to_str:N \l_@@_tone_tl _tl } } &gt;
          { 0 \cs_if_exist_use:c { c_@@_ \tl_to_str:n {#1} _tl } }
          { \tl_put_right:Nn \l_@@_post_tl {#1} }
          {
            \tl_set:Nn \l_@@_tone_tl {#1}
            \tl_set_eq:NN \l_@@_pre_tl \l_@@_item_tl
            \tl_clear:N \l_@@_post_tl
          }
        \tl_put_right:Nx \l_@@_item_tl { \@@_replace_v:n {#1} }
      }
    \@@_pinyin_aux:n
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_tone:nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_tone:nn #1#2
  { \use:c { @@_num_to_tone_ #1 :Nn } {#1} {#2} }
\cs_generate_variant:Nn \@@_tone:nn { V }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_replace_v:n}
%    \begin{macrocode}
\cs_new:Npn \@@_replace_v:n #1
  {
    \str_if_eq:nnTF {#1} { v }
      {
        \str_case:onTF { \l_@@_item_tl }
          { { l } { } { n } { } { L } { } { N } { } }
          { \exp_not:n { Ã¼ } } { u }
      }
      { \exp_not:n {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_pinyin_init:}
%    \begin{macrocode}
\cs_new:Npn \@@_pinyin_init:
  {
    \tl_clear:N \l_@@_pre_tl   \tl_clear:N \l_@@_post_tl
    \tl_clear:N \l_@@_item_tl  \tl_clear:N \l_@@_tone_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_if_number:nTF}
%    \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_number:n #1 { TF }
  {
    \if_int_compare:w \c_one_int &lt; 1 \tl_to_str:n {#1} \exp_stop_f:
      \prg_return_true: \else: \prg_return_false: \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_@@_first_bool}
%    \begin{macrocode}
\bool_new:N \l_@@_first_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
% {\c_@@_a_tl,\c_@@_o_tl,\c_@@_e_tl,\c_@@_i_tl,\c_@@_u_tl,\c_@@_v_tl}
%    \begin{macrocode}
\tl_const:Nn \c_@@_a_tl { 3 }
\tl_const:Nn \c_@@_o_tl { 2 }
\tl_const:Nn \c_@@_e_tl { 2 }
\tl_const:Nn \c_@@_i_tl { 1 }
\tl_const:Nn \c_@@_u_tl { 1 }
\tl_const:Nn \c_@@_v_tl { 1 }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_num_to_tone:Nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_num_to_tone:Nn #1#2
  {
    \if_case:w \int_eval:n { #2 - 1 } \exp_stop_f:
      \= {#1}  \or: \'{#1}  \or: \v {#1}  \or: \` {#1}  \else: #1 \fi:
  }
\tl_map_inline:nn { a o e u }
  { \cs_new_eq:cN { @@_num_to_tone_ #1 :Nn } \@@_num_to_tone:Nn }
\cs_new:Npn \@@_num_to_tone_i:Nn #1#2
  {
    \if_case:w \int_eval:n { #2 - 1 } \exp_stop_f:
      Ä«  \or: Ã­  \or: Ç  \or: Ã¬ \else: i \fi:
  }
\cs_new_protected:Npn \@@_num_to_tone_v:Nn #1#2
  {
    \str_case:onTF { \l_@@_pre_tl }
      { { l } { }  { n } { }  { L } { } { N } { } }
      {
        \if_case:w \int_eval:n { #2 - 1 } \exp_stop_f:
          Ç–  \or: Ç˜  \or: Çš  \or: Çœ \else: Ã¼ \fi:
      }
      { \@@_num_to_tone:Nn u {#2} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\xpinyinsetup}
%    \begin{macrocode}
\NewDocumentCommand \xpinyinsetup { m } { \keys_set:nn { xpinyin } {#1} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{ratio,vsep,hsep,pysep,font,format,multiple,footnote}
%    \begin{macrocode}
\clist_map_inline:nn
  { ratio , vsep , hsep , pysep , font , format , multiple }
  { \keys_define:nn { xpinyin } { #1 .tl_set:c = { l_@@_ #1 _tl } } }
\keys_define:nn { xpinyin }
  { footnote .bool_set:N = \l_@@_footnote_bool }
\keys_set:nn { xpinyin }
  {
    ratio   = .4 ,
    vsep    = 1 em ,
    pysep   = \c_space_tl ,
    font    = \normalfont ,
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\xpinyin_customary:nnn,\xpinyin_multiple:nnn}
%    \begin{macrocode}
\cs_new_protected:Npn \xpinyin_customary:nnn #1#2
  { \cs_gset_nopar:cpn { c_@@_ #2 _tl } }
\cs_new_protected:Npn \xpinyin_multiple:nnn #1#2
  { \cs_gset_nopar:cpn { c_@@_multiple_ #2 _clist } }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\group_begin:
  \cs_set_eq:NN \XPYU  \xpinyin_customary:nnn
  \cs_set_eq:NN \XPYUM \xpinyin_multiple:nnn
  \file_input:n { xpinyin-database.def }
\group_end:
%    \end{macrocode}
%
% \begin{macro}{\setpinyin}
%    \begin{macrocode}
\NewDocumentCommand \setpinyin { m m }
  {
    \tl_set:cn
      { c_@@_ \@@_char_to_unicode:n {#1} _tl }
      { \@@_pinyin:n {#2} }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\cs_if_exist:NTF \ProcessKeyOptions
  { \ProcessKeyOptions [ xpinyin ] }
  {
    \RequirePackage { l3keys2e }
    \ProcessKeysOptions { xpinyin }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/package&gt;
%    \end{macrocode}
%
% \section{\pkg{xpinyin.lua}}
%
%    \begin{macrocode}
%&lt;*lua&gt;
%    \end{macrocode}
%
%    \begin{macrocode}
xpinyin       = xpinyin or { }
local xpinyin = xpinyin
%    \end{macrocode}
%
% è®¡ç®—æ—¶åŒº\footnote{\url{http://lua-users.org/wiki/TimeZone}}ã€‚
%    \begin{macrocode}
xpinyin.tzoffset = "+0000"
do
  -- Compute the difference in seconds between local time and UTC.
  local function get_timezone()
    local now = os.time()
    return os.difftime(now, os.time(os.date("!*t", now)))
  end
  -- Return a timezone string in ISO 8601:2000 standard form (+hhmm or -hhmm)
  local function get_tzoffset(timezone)
    local h, m = math.modf(timezone / 3600)
    return string.format("%+.4d", 100 * h + 60 * m)
  end
  xpinyin.tzoffset = get_tzoffset(get_timezone())
end
%    \end{macrocode}
%
%    \begin{macrocode}
xpinyin = {
  uchar    = unicode.utf8.char,
  readings = { },
  fixreadings = {
%    \end{macrocode}
% ä¸ºæ±‰å­—â€œã€‡â€å¢žåŠ&nbsp;æ‹¼éŸ³ã€‚
%    \begin{macrocode}
    {"U+3007", "Mandarin", "lÃ­ng"}
  },
%    \end{macrocode}
%
%    \begin{macrocode}
  database = {
    source  = "http://www.unicode.org/Public/UNIDATA/Unihan.zip",
    file    = "Unihan_Readings.txt",
    date    = "Date: 2014-05-09 18:17:02 GMT [JHJ]",
    version = "Unicode version: 7.0.0",
    dbfile  = "xpinyin.db"
  },
  preamble = [[
%&lt;&lt;COMMENT
%%
%%  Do not edit this file!
%%  Created from Unihan database:
%%
%%    $file
%%    $date
%%    $version
%%
%%  by "texlua xpinyin.lua" on ]]
           .. os.date("%Y-%m-%d %X ") .. xpinyin.tzoffset
           .. "\n%%"
%COMMENT
}
%    \end{macrocode}
%
%    \begin{macrocode}
local http_request = require("socket.http").request
local ltn12_sink_file = require("ltn12").sink.file
local zip_open = require("zip").open
%    \end{macrocode}
%
% å°† \file{Unihan_Readings.txt}^^A
% \footnote{\url{http://http://www.unicode.org/reports/tr38/}ã€‚} ä¿å­˜åˆ°ä¸€å¼&nbsp;è¡¨é‡Œé¢ã€‚
%    \begin{macrocode}
function xpinyin.maketable (txt)
  local f = io.open(txt or xpinyin.database.file, "r")
  if not f then
    local source = xpinyin.database.source
    local zfilename = source:match("[^/]+$")
    local zfile = zip_open(zfilename)
    if not zfile then
      xpinyin.download(source, zfilename)
      zfile = assert(zip_open(zfilename))
    end
    f = assert(zfile:open(xpinyin.database.file))
    zfile:close()
  end
  local s, prop
  for line in f:lines() do
    s = line:explode("\t")
    if #s == 3 then
      prop = s[2]:sub(2)
      if prop == "Mandarin" or
         prop == "HanyuPinyin" or
         prop == "XHC1983" or
         prop == "HanyuPinlu" then
        xpinyin.insert(s[1], prop, s[3])
      end
    elseif line:find("Date") then
      xpinyin.database.date = line:match("^[#%s]*(.*)")
    elseif line:find("Unicode version:") then
      xpinyin.database.version = line:match("^[#%s]*(.*)")
    end
  end
  f:close()
  if xpinyin.fixreadings then
    for _, s in pairs(xpinyin.fixreadings) do
      xpinyin.insert(s[1], s[2], s[3])
    end
  end
end
%    \end{macrocode}
%
% ä¸‹è½½ \file{Unihan.zip}ã€‚
%    \begin{macrocode}
function xpinyin.download (source, zip)
  print("\nRetrieving Unihan Database from\n", source)
  local status, err = http_request{
    url  = source,
    sink = ltn12_sink_file(io.open(zip, "wb")) }
  if not status then
    error([[Download ']] .. zip .. [[' failed because of ]] .. err .. ".")
  end
end
%    \end{macrocode}
%
% å¾€æ‹¼éŸ³è¡¨ä¸­åŠ&nbsp;å…¥é¡¹ç›®ã€‚
%    \begin{macrocode}
function xpinyin.insert (unicode, prop, value)
  local index = tonumber(unicode:match("%x+$"), 16)
  if not xpinyin.readings[index] then
    xpinyin.readings[index] = { }
  end
  xpinyin.readings[index][prop] = value
end
%    \end{macrocode}
%
% è¾“å‡ºéœ€è¦çš„æ&nbsp;¼å¼æ–‡ä»¶ã€‚
%    \begin{macrocode}
function xpinyin.output (db)
  local f = assert(io.open(db or xpinyin.database.dbfile, "w"))
  local preamble = xpinyin.preamble:gsub("%$(%w+)", xpinyin.database)
  f:write(preamble, "\n")
  local hanzi, pinyin
  local mt = { }
  for index, pyt in xpinyin.pairsByKeys(xpinyin.readings) do
    pinyin = assert(xpinyin.grep(pyt))
    hanzi = xpinyin.uchar(index)
    f:write("\\XPYU{", hanzi, "}{", index, "}{", pinyin, "}\n")
    pinyin = xpinyin.multiple(pyt)
    if pinyin then
      mt[#mt + 1] = "\\XPYUM{" .. hanzi .. "}{" .. index .. "}{" .. pinyin .."}"
    end
  end
  f:write(table.concat(mt, "\n"), "\n")
  f:close()
end
%    \end{macrocode}
%
% å°†è¡¨æŒ‰ç…§ç´¢å¼•æŽ’åºï¼Œä»£ç&nbsp;æ¥æºäºŽ
% \href{http://www.lua.org/pil/19.3.html}{\textit{Programming in Lua}}ã€‚
%    \begin{macrocode}
function xpinyin.pairsByKeys (t, f)
  local a = { }
  for n in pairs(t) do a[#a + 1] = n end
  table.sort(a, f)
  local i = 0 -- iterator variable
  return function () -- iterator function
    i = i + 1
    return a[i], t[a[i]]
  end
end
%    \end{macrocode}
%
% æŒ‰ç…§ \texttt{Mandarin}ã€\texttt{XHC1983}ã€\texttt{HanyuPinyin}
% çš„é¡ºåºé€‰æ‹©æœ€å¸¸ç”¨çš„æ‹¼éŸ³ã€‚\texttt{HanyuPinlu} çš„è´¨é‡è¾ƒå·®ï¼Œä¸é‡‡ç”¨ã€‚
%    \begin{macrocode}
function xpinyin.grep (pyt)
  if pyt.Mandarin then
    return pyt.Mandarin:match("%S+"), "Mandarin"
  elseif pyt.XHC1983 then
    return pyt.XHC1983:match(":(%S+)"), "XHC1983"
  elseif pyt.HanyuPinyin then
    return pyt.HanyuPinyin:match(":([^,%s]+)"), "HanyuPinyin"
  end
end
%    \end{macrocode}
%
% æ&nbsp;¹æ® \texttt{XHC1983} å’Œ \texttt{HanyuPinyin} é€‰å‡ºå¤šéŸ³å­—ã€‚
%    \begin{macrocode}
function xpinyin.multiple (pyt)
  if pyt.XHC1983 then
    local s = pyt.XHC1983:explode()
    if s[2] then
      local t = { }
      for i, v in ipairs(s) do
        t[#t + 1] = v:explode(":")[2]
      end
      return xpinyin.unique(t), "XHC1983"
    end
  elseif pyt.HanyuPinyin and pyt.HanyuPinyin:find("%D,") then
    local t = { }
    for _, v in ipairs(pyt.HanyuPinyin:explode()) do
      for _, py in ipairs(v:explode(":")[2]:explode(",")) do
        t[#t + 1] = py
      end
    end
    return xpinyin.unique(t), "HanyuPinyin"
  end
end
%    \end{macrocode}
%
% åˆ&nbsp;é™¤æŽ‰æ•°ç»„ä¸­çš„é‡å¤å…ƒç´&nbsp;ã€‚
%    \begin{macrocode}
function xpinyin.unique (t)
  local rt = xpinyin.remove_duplicate(t)
  if #rt &gt; 1 then
    return table.concat(rt, ",")
  end
end
function xpinyin.remove_duplicate (t)
  local ht = { }
  local nt = { }
  for i, v in ipairs(t) do
    if not ht[v] then
      nt[#nt + 1] = v
      ht[v] = true
    end
  end
  return nt
end
%    \end{macrocode}
%
%    \begin{macrocode}
xpinyin.maketable()
%    \end{macrocode}
%
%    \begin{macrocode}
xpinyin.output()
%    \end{macrocode}
%
%    \begin{macrocode}
%&lt;/lua&gt;
%    \end{macrocode}
%
% \end{implementation}
%
% \Finale
%
\endinput
</pre></body></html>