diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/newunicodechar/newunicodechar.dtx |
Initial commit
Diffstat (limited to 'macros/latex/contrib/newunicodechar/newunicodechar.dtx')
-rw-r--r-- | macros/latex/contrib/newunicodechar/newunicodechar.dtx | 471 |
1 files changed, 471 insertions, 0 deletions
diff --git a/macros/latex/contrib/newunicodechar/newunicodechar.dtx b/macros/latex/contrib/newunicodechar/newunicodechar.dtx new file mode 100644 index 0000000000..3875a206af --- /dev/null +++ b/macros/latex/contrib/newunicodechar/newunicodechar.dtx @@ -0,0 +1,471 @@ +% \iffalse meta-comment +% +% Copyright (C) 2011-2018 by Enrico Gregorio +% <Enrico dot Gregorio at univr dot it> +% ------------------------------------------------------- +% +% 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. 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 Enrico Gregorio. +% +% This work consists of the files +% newunicodechar.dtx +% newunicodechar.ins +% and the derived file newunicodechar.sty. +% +% \fi +% +% \iffalse +%<*driver> +\ProvidesFile{newunicodechar.dtx} +%</driver> +%<package>\NeedsTeXFormat{LaTeX2e}[2018/04/01] +%<package>\ProvidesPackage{newunicodechar} +%<*package> + [2018/04/08 v1.2 Defining Unicode characters] +%</package> +% +%<*driver> +\documentclass{ltxdoc} +\usepackage[T1]{fontenc} +\usepackage{metalogo,booktabs,lmodern,textcomp,wasysym} +\EnableCrossrefs +\CodelineIndex +\RecordChanges +\begin{document} + \DocInput{newunicodechar.dtx} + \PrintChanges + \PrintIndex +\end{document} +%</driver> +% \fi +% +% \CheckSum{201} +% +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% \changes{v1.2}{2018/04/08}{Now utf8 is default} +% \changes{v1.1}{2012/11/12}{Added support for \mbox{\textsf{inputenx}}} +% \changes{v1.0}{2011/02/15}{Initial version} +% +% \GetFileInfo{newunicodechar.dtx} +% +% \DoNotIndex{\newcommand,\newenvironment,\!,\@empty,\@gobble,\@gobbletwo} +% \DoNotIndex{\@ifpackageloaded,\@ifpackagewith,\@ifundefined,\@namedef} +% \DoNotIndex{\@nil,\@onlypreamble,\@tempa,\@tempb,\@tempswafalse,\def} +% \DoNotIndex{\@tempswatrue,\^,\-,\active,\begingroup,\catcode,\@car,\@cdr} +% \DoNotIndex{\edef,\else,\endgroup,\endinput,\expandafter,\fi,\if} +% \DoNotIndex{\if@tempswa,\ifcase,\ifnum,\ifx,\lccode,\let,\lowercase} +% \DoNotIndex{\MessageBreak,\next,\number,\numexpr,\or,\PackageError} +% \DoNotIndex{\PackageWarning,\PackageWarningNoLine,\strip@prefix,\@@end} +% \DoNotIndex{\relax,\space,\string,\DeclareOption,\ProcessOptions} +% \DoNotIndex{\meaning,\ifdefined,\csname,\chardef,\endcsname,\protect} +% +% \title{The \textsf{newunicodechar} package\thanks{This document +% corresponds to \textsf{newunicodechar}~\fileversion, dated \filedate.}} +% \author{Enrico Gregorio \\ \texttt{Enrico dot Gregorio at univr dot it}} +% +% \maketitle +% +% \section{Introduction} +% +% When using Unicode input with \LaTeX{} it's not so uncommon to get an +% incomprehensible error message such as +%\begin{verbatim} +%Unicode char \u8:xxx not set up for use with LaTeX +%\end{verbatim} +% where |xxx| may be the actual character we input or a combination of +% strange characters. This happens because the \texttt{utf8} option +% given to \textsf{inputenc} or \textsf{inputenx} defines the \LaTeX{} +% meaning of many Unicode characters, but, of course, not all of them. +% +% For example, one might want to write some Latin words with prosodic +% marks, i.e., the diacritics that tell whether a vowel is long or +% short, in order to distinguish between `p\u{o}p\u{u}lus' (people) +% and `p\=op\u{u}lus' (poplar), but using the actual Unicode +% characters that make the \LaTeX{} document easier to read; look at +% the following table, where on the left the input is via the \LaTeX{} +% Internal Character Representation (LICR) and on the right it's via +% Unicode characters, +% \begin{center} +% \begin{tabular}{cc} +% \toprule +% LICR & Unicode \\ +% \midrule +% \verb|p\u{o}p\u{u}lus| & \texttt{p\u{o}p\u{u}lus}\\ +% \verb|p\={o}p\u{u}lus| & \texttt{p\={o}p\u{u}lus}\\ +% \bottomrule +% \end{tabular} +% \end{center} +% and judge by yourselves which one is better. Unfortunately, the +% \texttt{utf8} option to \textsf{inputenc} doesn't define a meaning +% for \texttt{\u{o}}, \texttt{\={o}}, and \texttt{\u{u}}. As a matter +% of fact, only \texttt{\u{a}} and \texttt{\u{A}} are defined, as they +% are used in the Romanian language. +% +% One might resort to |\DeclareUnicodeCharacter| in the document's +% preamble, but this requires looking up at the (long) list of Unicode +% characters and jotting down the relevant numbers. For example, +% \texttt{\u{o}} is \texttt{U+014F}, so the declaration +%\begin{verbatim} +%\DeclareUnicodeCharacter{014F}{\u{o}} +%\end{verbatim} +% would do for \texttt{\u{o}}. +% +% The present package introduces a simpler interface that frees the +% user from the burden to look up in the tables: all it's needed is +% \begin{flushleft} +% |\newunicodechar{|\texttt{\u{o}}|}{\u{o}}| +% \end{flushleft} +% You are not restricted to definition like this: for example, +% \eighthnote{}~is Unicode \texttt{U+266A}, but you are not required +% to know it: if your editor can insert the character~\eighthnote, you +% may define its meaning by loading a package that provides it and say +% \begin{flushleft} +% |\usepackage{wasysym}|\\ +% |\newunicodechar{|\eighthnote|}{\eighthnote}| +% \end{flushleft} +% Important note: the package will not work if the \textsf{inputenc} package +% is called with an option different from \texttt{utf8}. As of April 2018, +% this encoding is assumed by default in 8~bit \TeX{} engines when running +% \LaTeX. However one can still load \textsf{inputenc} or \textsf{inputenx} +% with the \texttt{utf8} option (not \texttt{utf8x}). +% +% A similar problem may arise even with \XeLaTeX{}. A frequently asked +% question on mailing lists or discussion groups is how to print some +% particular character in a different font than the main one of the +% document, say, for example, the Euro sign which, in some fonts, is +% horrible. The usual answer is to write something like +% \begin{flushleft} +% |\newfontfamily{\eurofont}{|\meta{some font}|}|\\ +% |\catcode`|\texttt{\texteuro}|=\active|\\ +% |\protected\def |\texttt{\texteuro}|{{\eurofont\char`\|^^A +% \texttt{\texteuro}|}}| +% \end{flushleft} +% which, for the average user, is somewhat scaring. With +% \textsf{newunicodechar} this may be simplified into +% \begin{flushleft} +% |\newfontfamily{\eurofont}{|\meta{some font}|}|\\ +% |\newunicodechar{|\texttt{\texteuro}|}{{\eurofont\texteuro}}| +% \end{flushleft} +% +% \section{Usage} +% +% The package requires the use of a Unicode engine, i.e., \XeLaTeX{} +% or \LuaLaTeX{}, or, with (pdf)\LaTeX{}, the \textsf{inputenc} or +% \textsf{inputenx} package along with the \texttt{utf8} option. It +% won't work with the \texttt{utf8x} option that employs a completely +% different mechanism for parsing Unicode characters in +% (pdf)\LaTeX{}. It should be said that \texttt{utf8x} defines many +% more characters than \texttt{utf8}, so that the present package +% wouldn't be needed. +% +% Of course the \LaTeX{} document must be written using a Unicode +% savvy editor. +% +% \bigskip +% +% The package has only one option, \texttt{verbose}^^A +% \marginpar{\raggedleft\texttt{verbose}}^^A +% \index{verbose=\texttt{verbose} option|usage}, which is off by +% default. If the package is called by +% |\usepackage[verbose]{newunicodechar}|, then the informative message +% on the log file will show the old definition along with the warning +% about the redefinition. Unfortunately this definition usually has a +% rather cryptic format; for example, redefining \texttt{\u{a}} would +% print +%\begin{verbatim} +%Redefining Unicode character; it meant +%*** \IeC {\u a} *** +%before your redefinition on input line 22. +%\end{verbatim} +% Call the package with this option if you are worried about what you +% are redefining, but the meaning of the Unicode character should +% correspond easily to just one LICR entry. This option does nothing +% when a Unicode engine is used, because no character is active +% initially (except for~|~|), so there should be non risk to redefine +% anything. +% +% \DescribeMacro{\newunicodechar} +% The package provides only one command, |\newunicodechar|, which must +% be called with two arguments: +% \begin{flushleft} +% |\newunicodechar{|\meta{char}|}{|\meta{code}|}| +% \end{flushleft} +% where \meta{char} is the Unicode character to which we need to give +% a meaning and \meta{code} is that meaning, that is the \LaTeX{} code +% that will be substituted to the character. Here is what's needed for +% the prosodic marks in Latin: +% \begin{flushleft} +% |%\newunicodechar{|\texttt{\u{A}}|}{\u{A}}| +% |\newunicodechar{|\texttt{\u{a}}|}{\u{a}}|\\ +% |\newunicodechar{|\texttt{\u{E}}|}{\u{E}}| +% |\newunicodechar{|\texttt{\u{e}}|}{\u{e}}|\\ +% |\newunicodechar{|\texttt{\u{I}}|}{\u{I}}| +% |\newunicodechar{|\texttt{\u{\i}}|}{\u{\i}}|\\ +% |\newunicodechar{|\texttt{\u{O}}|}{\u{O}}| +% |\newunicodechar{|\texttt{\u{o}}|}{\u{o}}|\\ +% |\newunicodechar{|\texttt{\u{U}}|}{\u{U}}| +% |\newunicodechar{|\texttt{\u{u}}|}{\u{u}}|\\ +% |\newunicodechar{|\texttt{\={A}}|}{\={A}}| +% |\newunicodechar{|\texttt{\={a}}|}{\={a}}|\\ +% |\newunicodechar{|\texttt{\={E}}|}{\={E}}| +% |\newunicodechar{|\texttt{\={e}}|}{\={e}}|\\ +% |\newunicodechar{|\texttt{\={I}}|}{\={I}}| +% |\newunicodechar{|\texttt{\={\i}}|}{\={\i}}|\\ +% |\newunicodechar{|\texttt{\={O}}|}{\={O}}| +% |\newunicodechar{|\texttt{\={o}}|}{\={o}}|\\ +% |\newunicodechar{|\texttt{\={U}}|}{\={U}}| +% |\newunicodechar{|\texttt{\={u}}|}{\={u}}| +% \end{flushleft} +% The first line is commented out, because those characters are +% already defined. It doesn't hurt to give again a definition, +% \LaTeX{} will just warn about it. +% +% Caution: when used with \XeLaTeX{} or \LuaLaTeX{}, there will be no +% warning, but the standard setup doesn't define any active character. +% +% The first argument \emph{must} consist of a single Unicode +% character, but the package checks for it and raises an error +% otherwise; it will raise an error also if the first argument +% consists of a plain ASCII character: defining them is not allowed in +% (pdf)\LaTeX{} and would break almost everything in \XeLaTeX{} or +% \LuaLaTeX{}. +% +% \section{An easier way?} +% +% One could dispense with this package, since the same effect may be +% obtained in the way we have already seen in \XeLaTeX{} or \LuaLaTeX{}; +% with (pdf)\LaTeX{}, calling |\newunicodechar{|\texttt{\={u}}|}{\={u}}| +% is equivalent to say +% \begin{flushleft} +% |\makeatletter|\\ +% |\@namedef{u8:\detokenize{|\texttt{\={u}}|}}{\={u}}|\\ +% |\makeatother| +% \end{flushleft} +% +% \StopEventually{} +% +% \section{Implementation} +% +% The usual presentation, that we repeat here for completeness. +%\begin{verbatim} +%\ProvidesFile{newunicodechar.dtx} +%\NeedsTeXFormat{LaTeX2e}[2008/04/05] +%\ProvidesPackage{newunicodechar} +%\end{verbatim} +% The date for the format has been chosen to match the last version of +% the \texttt{utf8enc.dfu} file that provides definitions for Unicode +% characters. +% +% Now the real macros. First of all we check that the typesetting +% engine is sufficiently recent to include $\varepsilon$-\TeX{} +% extensions. +% \begin{macrocode} +\@ifundefined{eTeXversion} + {\PackageError{newunicodechar}{LaTeX engine too old, aborting} + {Please upgrade your TeX system}\@@end}{} +% \end{macrocode} +% +% \subsection{Options} +% There's only one option. +% \begin{macrocode} +\DeclareOption{verbose}{\let\nuc@verbose=T} +\ProcessOptions\relax +% \end{macrocode} +% \subsection{Error messages} +% \begin{macrocode} +\def\nuc@onebyteerr{\PackageError{newunicodechar} + {ASCII character requested} + {Only characters above U+007F may be defined; you asked + for\MessageBreak a plain ASCII character and your definition + has been ignored.}} +\def\nuc@emptyargerr{\PackageError{newunicodechar} + {Empty argument} + {You shouldn't write \protect\newunicodechar{}{...}}} +\def\nuc@invalidargerr{\PackageError{newunicodechar} + {Invalid argument} + {The first argument to \protect\newunicodechar\space is + either\MessageBreak too long or an invalid sequence of bytes}} +% \end{macrocode} +% +% \subsection{Unicode engines} +% In case we are running a Unicode engine (\texttt{xelatex} or +% \texttt{lualatex}), the definition of the main macro is easier: we +% check whether the character is above $127$ and, in this case, we +% make it active expanding to the second argument. This definition of +% the main macro will be seen only if the engine has the |^^^^| +% convention for inputting characters in hexadecimal format, so that +% |^^^^0021| is one token and |\@gobble| will eat it up, making +% |\next| equal to |\@empty|; with an eight bit engine (\texttt{latex} +% or \texttt{pdflatex}), |\@gobble| will swallow only |^^^|. +% +% In this case we define the main macro all in one swoop; first we +% check that the first argument is nonempty, then we act only if it +% consists of only one (character) token. Then if the charcode of this +% token is less than $127$ we emit an error message; otherwise we +% activate the character and define its (protected) expansion to be +% the second argument. The last action, in this case, is to allow +% |\newunicodechar| only in the preamble. Then we do |\endinput|. If +% the engine is not Unicode savvy, everything up to the closing |\fi| +% is swallowed up. +% +% \begin{macro}{\newunicodechar} +% Here is the code for defining the Unicode engine version of the main +% macro. Notice that we try being on the safe side by not assuming any +% particular category code for~|~|, because we restore it after giving +% the definition where we need it to be active. +% \begin{macrocode} +\begingroup +\catcode`\^=7 \catcode30=12 \catcode`\!=12 % for safety +\edef\next{\@gobble^^^^0021} +\expandafter\endgroup +\ifx\next\@empty % Start of code for Unicode engines +\chardef\nuc@atcode=\catcode`\~ +\catcode`\~=\active +\def\newunicodechar#1#2{% + \if\relax\detokenize{#1}\relax + \nuc@emptyargerr + \else + \if\relax\detokenize\expandafter{\@cdr#1\@nil}\relax + \ifnum`#1>\string"7F + \catcode`#1=\active + \begingroup\lccode`\~=`#1 + \lowercase{\endgroup\protected\def~}{#2}% + \else + \nuc@onebyteerr + \fi + \else + \nuc@invalidargerr + \fi + \fi} +\catcode`\~=\nuc@atcode +\@onlypreamble\newunicodechar +\expandafter\endinput +\fi % End of code for Unicode engines +% \end{macrocode} +% \end{macro} +% +% \subsection{Eight bit engines} +% From now on we can assume an eight bit engine is used; we check that +% \textsf{inputenc} or \textsf{inputenx} has been loaded with the +% right option, otherwise we define |\newunicodechar| to swallow its +% arguments, after a warning. We need to first check for +% \textsf{inputenx} because it loads \textsf{inputenc}. +% \changes{v1.2}{2018/04/08}{Now utf8 is default} +% \changes{v1.1}{2012/11/12}{Added support for \mbox{\textsf{inputenx}}} +% \begin{macrocode} +\def\nuc@stop{\PackageWarningNoLine{newunicodechar} + {This package only works if the document\MessageBreak + encoding is `utf8'}% + \let\newunicodechar\@gobbletwo\endinput} +\edef\@tempa{\detokenize{utf8}} +\edef\@tempb{\detokenize\expandafter{\inputencodingname}} +\ifx\@tempb\@tempa\else + \nuc@stop +\fi +% \end{macrocode} +% \begin{macro}{\newunicodechar} +% The main macro. We set the temporary switch to false and put in +% |\nuc@tempa| the first argument, but detokenized, since it consists of +% active characters. We check that it's not empty and access to its +% first token that we put into |\@tempb|. Then we call |\nuc@check| +% and if it sets the temporary switch to true, we execute the +% definition, since the first argument is a valid UTF-8 character, but +% we issue a warning if it already has a meaning. All we need to do is +% to define the macro |\csname u8:\nuc@tempa\endcsname|, because that's +% how \textsf{inputenc} acts. The part between |\ifdefined| and the +% corresponding |\fi| will be executed only with the \texttt{verbose} +% option. +% \begin{macrocode} +\def\newunicodechar#1#2{% + \@tempswafalse + \edef\nuc@tempa{\detokenize{#1}}% + \if\relax\nuc@tempa\relax + \nuc@emptyargerr + \else + \edef\@tempb{\expandafter\@car\nuc@tempa\@nil}% + \nuc@check + \if@tempswa + \@ifundefined{u8:\nuc@tempa}{} + {\PackageWarning{newunicodechar} + {Redefining Unicode character\ifdefined\nuc@verbose; + it meant\MessageBreak + ***\space\space\nuc@meaning\space\space***\MessageBreak + before your redefinition\fi}}% + \@namedef{u8:\nuc@tempa}{#2}% + \fi + \fi +} +% \end{macrocode} +% \end{macro} +% The first helper macro computes the number of bytes in the first +% argument, though it appears to the user as a single character. The +% third is used for the \texttt{verbose} option. +% \begin{macrocode} +\def\nuc@getlength#1{% + \ifx#1\@nil + \expandafter\relax + \else + +1\expandafter\nuc@getlength + \fi} +\ifdefined\nuc@verbose + \def\nuc@meaning{\expandafter\expandafter\expandafter + \strip@prefix\expandafter\meaning\csname u8:\nuc@tempa\endcsname} +\fi +% \end{macrocode} +% We select the action based on the length of the first argument; in +% case only one byte appears, the user is trying to define an ASCII +% character, which is not allowed; if the input is two, three, or four +% bytes long, we check whether the first byte has the correct form: +% its binary form must be, respectively, \texttt{110xxxxx}, +% \texttt{1110xxxx}, or \texttt{11110xxx}, so not less than $192$, +% $224$, or $240$. The macro |\nuc@ch@ck| does precisely this, issuing +% an error message if the argument is invalid or else setting the +% temporary switch to true. +% \begin{macrocode} +\def\nuc@check{% + \ifcase\numexpr0\expandafter\nuc@getlength\nuc@tempa\@nil + \or %0 + \nuc@onebyteerr\or %1 + \nuc@ch@ck{192}\or %2 + \nuc@ch@ck{224}\or %3 + \nuc@ch@ck{240}\else %4 + \nuc@invalidargerr + \fi} +\def\nuc@ch@ck#1{% + \expandafter\ifnum\expandafter`\@tempb<#1\relax + \nuc@invalidargerr + \else + \@tempswatrue + \fi +} +% \end{macrocode} +% Finally we disallow |\newunicodechar| outside the preamble. +% \begin{macrocode} +\@onlypreamble\newunicodechar +% \end{macrocode} +% \Finale +\endinput |