summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/unic-ini.tex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/unic-ini.tex')
-rw-r--r--Master/texmf-dist/tex/context/base/unic-ini.tex667
1 files changed, 667 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/unic-ini.tex b/Master/texmf-dist/tex/context/base/unic-ini.tex
new file mode 100644
index 00000000000..1881eceb2f4
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/unic-ini.tex
@@ -0,0 +1,667 @@
+%D \module
+%D [ file=unic-ini,
+%D version=2002.12.03,
+%D title=\CONTEXT\ \UNICODE\ Support,
+%D subtitle=\UNICODE\ \& UTF-8 support,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{Context UNICODE Macros (ini)}
+
+%D Sorry, we only support his in \ETEX.
+
+\beginTEX
+ \def\useunicodevector[#1]{}
+ \expandafter \endinput
+\endTEX
+
+\unprotect
+
+%D This module deals with unicode, and in particular with
+%D \UTF-8 conversion. The prelude to this module was \type
+%D {xtag-utf}, which is now replaced by a one||liner. The
+%D macros below deal with conversions. Thanks to Taco for
+%D providing the following conversion rules.
+%D
+%D \starttabulate[|c|c|c|c|c|]
+%D \NC $b_1$ \NC $b_2$ \NC $b_3$ \NC $b_4$ \NC unicode \NC \NR
+%D \NC192---223\NC128---191\NC \NC \NC 0x80---0x7FF \NC \NR
+%D \NC224---239\NC128---191\NC128---191\NC \NC 0x800---0xFFFF \NC \NR
+%D \NC240---247\NC128---191\NC128---191\NC128---191\NC0x10000---0x1FFFF\NC \NR
+%D \stoptabulate
+%D
+%D In \UTF-8 the characters in the range 128---191 are illegal
+%D as first characters. The characters 254 and 255 are
+%D completely illegal and should not appear at all (they are
+%D related to UTF16).
+%D
+%D The unicode number for an \UTF-8 sequence can be calculated
+%D as follows:
+%D
+%D \starttabulate[|mc|m|mc|m|mc|m|mc|m|]
+%D \NC b_1 \NC \NC \NC \NC \NC \NC \NC if b_1<=127\NC \NR
+%D \NC 64(b_1-192)\NC+\NC (b_2-128)\NC \NC \NC \NC \NC if 192<=b1<=223\NC \NR
+%D \NC 4096(b_1-224)\NC+\NC 64(b_2-128)\NC+\NC (b_3-128)\NC \NC \NC if 224<=b1<=239\NC \NR
+%D \NC262144(b_1-240)\NC+\NC4096(b_2-128)\NC+\NC64(b_3-128)\NC+\NC(b_4-128)\NC if 240<=b1<=247\NC \NR
+%D \stoptabulate
+%D
+%D A lot of information about unicode can be found on the
+%D web (search for Markus Kuhn and unicode and you'll
+%D probably end up at the right place).
+
+%D In \ETEX\ vocabulary such a conversion looks as follows.
+%D We need the \type {`} in order to turn a character into a
+%D number.
+%D
+%D \starttyping
+%D \def\utftwounicode#1#2%
+%D {\number\numexpr (64*(\numexpr (#1-192))+%
+%D (\numexpr(`#2-128)))}
+%D
+%D \def\utfthreeunicode#1#2#3%
+%D {\number\numexpr (4096*(\numexpr (#1-224))+
+%D 64*(\numexpr(`#2-128))+%
+%D (\numexpr(`#3-128)))}
+%D
+%D \def\utffourunicode#1#2#3#4%
+%D {\number\numexpr(262144*(\numexpr (#1-240))+
+%D 4096*(\numexpr(`#1-128))+
+%D 64*(\numexpr(`#2-128))+%
+%D (\numexpr(`#3-128)))}
+%D \stoptyping
+%D
+%D When we map the unicode number on one of the 256 char wide
+%D unicode tables, we need to do a bit of div and mod. Watch
+%D out: an \ETEX\ \type {/} is not the same as \TEX's \type
+%D {\divide}. The former rounds, while the later truncates, so
+%D we need to trucate ourselves. In case you wonder why we
+%D use \type {\numexpr}: this is not only more convenient, but
+%D also makes it possible to avoid scratch counters, so that we
+%D get fast and fully expandable conversions.
+%D
+%D \starttyping
+%D \def\utfdiv#1{\number\numexpr((#1-128)/256)}
+%D \def\utfmod#1{\number\numexpr((#1)-(256*(\utfdiv{#1})))}
+%D \stoptyping
+%D
+%D So far for the readable alternatives. When using \type
+%D {\numexpr} you should be aware of rather unexpected look
+%D ahead effects. The next implementation uses registers,
+%D which saves tokens and is faster. In this case we gain
+%D some 10\% time.
+
+\chardef \utf@a= 64
+\mathchardef \utf@b= 4096
+\newcount\utf@c\utf@c=262144
+\chardef \utf@d= 192
+\chardef \utf@e= 224
+\chardef \utf@f= 240
+\chardef \utf@g= 128
+\mathchardef \utf@h= 256
+\chardef \utf@i= 127
+\mathchardef \utf@j= 2048
+
+%D The definitions now become:
+%D
+%D \starttyping
+%D \def\utftwounicode#1#2%
+%D {\number\numexpr(\utf@a*(\numexpr (#1-\utf@d))+%
+%D (\numexpr(`#2-\utf@g)))}
+%D
+%D \def\utfthreeunicode#1#2#3%
+%D {\number\numexpr(\utf@b*(\numexpr (#1-\utf@e))+
+%D \utf@a*(\numexpr(`#2-\utf@g))+%
+%D (\numexpr(`#3-\utf@g)))}
+%D
+%D \def\utffourunicode#1#2#3#4%
+%D {\number\numexpr(\utf@c*(\numexpr (#1-\utf@f))+
+%D \utf@b*(\numexpr(`#2-\utf@g))+
+%D \utf@a*(\numexpr(`#3-\utf@g))+%
+%D (\numexpr(`#4-\utf@g)))}
+%D \stoptyping
+%D
+%D And:
+%D
+%D \starttyping
+%D \def\utfdiv#1{\number\numexpr((#1-\utf@g)/\utf@h)}
+%D \def\utfmod#1{\number\numexpr((#1)-(\utf@h*(\utfdiv{#1})))}
+%D \stoptyping
+%D
+%D Depending on the usage, you can rely on parenthesis only:
+%D
+%D \starttyping
+%D \def\utftwounicode#1#2%
+%D {\numexpr(\utf@a*(#1-\utf@d)+%
+%D `#2-\utf@g)}
+%D
+%D \def\utfthreeunicode#1#2#3%
+%D {\numexpr(\utf@b*(#1-\utf@e)+%
+%D \utf@a*(`#2-\utf@g)+%
+%D `#3-\utf@g)}
+%D
+%D \def\utffourunicode#1#2#3#4%
+%D {\numexpr(\utf@c*(#1-\utf@f)+%
+%D \utf@b*(`#2-\utf@g)+%
+%D \utf@a*(`#3-\utf@g)+%
+%D `#4-\utf@g)}
+%D \stoptyping
+
+\def\utfdiv#1{\the\numexpr (#1-\utf@g)/\utf@h \relax}
+\def\utfmod#1{\the\numexpr#1-\utf@h*((#1-\utf@g)/\utf@h)\relax}
+
+%D The next one also handles the zero case well:
+
+\def\utfdiv#1{\the\numexpr\ifcase\numexpr#1\relax0\else (#1-\utf@g)/\utf@h \fi\relax}
+\def\utfmod#1{\the\numexpr\ifcase\numexpr#1\relax0\else#1-\utf@h*((#1-\utf@g)/\utf@h)\fi\relax}
+
+% or
+%
+% \def\utfdiv#1{\ifcase\numexpr#1\relax0\else\the\numexpr(#1-\utf@g)/\utf@h\relax\fi}
+% \def\utfmod#1{\ifcase\numexpr#1\relax0\else\the\numexpr#1-\utf@h*((#1-\utf@g)/\utf@h)\relax\fi}
+
+%D When tracing we also need:
+
+\def\utfvid#1{\the\numexpr(#1-\medcard)/\maxcard\relax}
+
+%D Using the three conversion macros, we can now implement
+%D a few handlers. They all call the general \type
+%D {\unicodechar} conversion macro.
+%D
+%D \starttyping
+%D \def\utftwouniglph#1#2%
+%D {\unicodechar{\utftwounicode {#1}{#2}}}
+%D
+%D \def\utfthreeuniglph#1#2#3%
+%D {\unicodechar{\utfthreeunicode{#1}{#2}{#3}}}
+%D
+%D \def\utffouruniglph#1#2#3#4%
+%D {\unicodechar{\utffourunicode {#1}{#2}{#3}{#4}}}
+%D \stoptyping
+%D
+%D Because the unicode number is used a few times per
+%D conversion, we can expand it once (\type {\the} and \type
+%D {\number} make sure of this). This saves us another 10\%.
+%D
+%D \starttyping
+%D \def\utftwouniglph#1#2%
+%D {\@EA\unicodechar\@EA{\the\utftwounicode{#1}{#2}}}
+%D
+%D \def\utfthreeuniglph#1#2#3%
+%D {\@EA\unicodechar\@EA{\the\utfthreeunicode{#1}{#2}{#3}}}
+%D
+%D \def\utffouruniglph#1#2#3#4%
+%D {\@EA\unicodechar\@EA{\the\utffourunicode{#1}{#2}{#3}{#4}}}
+%D \stoptyping
+%D
+%D We can rewrite these macros to faster alternatives: the
+%D less arguments we pass, the faster the conversion will be,
+%D but at the price of readability. So we have:
+%D
+%D \starttyping
+%D \def\utftwouniglph#1#2%
+%D {\@EA\unicodechar\@EA{\the\numexpr(\utf@a*(#1-\utf@d)+%
+%D `#2-\utf@g)}}
+%D
+%D \def\utfthreeuniglph#1#2#3%
+%D {\@EA\unicodechar\@EA{\the\numexpr(\utf@b*(#1-\utf@e)+%
+%D \utf@a*(`#2-\utf@g)+`#3-\utf@g)}}
+%D
+%D \def\utffouruniglph#1#2#3#4%
+%D {\@EA\unicodechar\@EA{\the\numexpr(\utf@c*(#1-\utf@f)+%
+%D \utf@b*(`#2-\utf@g)+\utf@a*(`#3-\utf@g)+`#4-\utf@g)}}
+%D \stoptyping
+%D
+%D Less parsing, and therefore faster:
+
+\def\utftwouniglph#1#2%
+ {\@EA\unicodechar\@EA{\the\numexpr\utf@a*(#1-\utf@d)+%
+ `#2-\utf@g\relax}}
+
+\def\utfthreeuniglph#1#2#3%
+ {\@EA\unicodechar\@EA{\the\numexpr\utf@b*(#1-\utf@e)+%
+ \utf@a*(`#2-\utf@g)+`#3-\utf@g\relax}}
+
+\def\utffouruniglph#1#2#3#4%
+ {\@EA\unicodechar\@EA{\the\numexpr\utf@c*(#1-\utf@f)+%
+ \utf@b*(`#2-\utf@g)+\utf@a*(`#3-\utf@g)+`#4-\utf@g\relax}}
+
+%D Now we come to the unicode handler itself. We will use a few
+%D constants, which saves us (at least at the time of writing
+%D and testing these macros) another 10\%.
+
+\def\@@univector {univ}
+\def\@@unknownchar{unknownchar}
+
+%D Now comes the nice part: turning codes into glyphs. The
+%D actual conversion does not take place here, but is done by
+%D macros in \type{unic-nnn} files. There we map a range onto
+%D named glyphs, so that they fit well into the rest of
+%D \CONTEXT.
+
+%D \macros
+%D {utfunicodetracer}
+%D
+%D By default, the converter produces a character representation,
+%D but for tracing purposes, you can set a trace option.
+
+\chardef\utfunicodetracer=0
+
+%D \def\TraceUnic#1%
+%D {\chardef\utfunicodetracer#1\relax\enableregime[utf]Ű}
+%D
+%D \starttabulate[|c|c|c|c|c|c|]
+%D \NC option \NC number\NC mapping\NC glyph\NC string\NC example \NC \NR
+%D \NC 0 \NC \NC \NC \star\NC \NC \TraceUnic0\NC \NR
+%D \NC 1 \NC \star \NC \NC \NC \NC \TraceUnic1\NC \NR
+%D \NC 2 \NC \NC \star \NC \NC \NC \TraceUnic2\NC \NR
+%D \NC 3 \NC \star \NC \star \NC \NC \NC \TraceUnic3\NC \NR
+%D \NC 4 \NC \star \NC \NC \star\NC \NC \TraceUnic4\NC \NR
+%D \NC 5 \NC \NC \star \NC \star\NC \NC \TraceUnic5\NC \NR
+%D \NC 6 \NC \star \NC \star \NC \star\NC \NC \TraceUnic6\NC \NR
+%D \NC 7 \NC \NC \NC \NC \star \NC \TraceUnic7\NC \NR
+%D \NC 8 \NC \star \NC \NC \NC \NC \TraceUnic8\NC \NR
+%D \NC otherwise\NC \NC \NC \star\NC \NC \TraceUnic9\NC \NR
+%D \stoptabulate
+
+%D \macros
+%D {unicodechar}
+%D
+%D Next we implement the character handler:
+
+\def\unicodechar
+ {\ifcase\utfunicodetracer
+ \expandafter\utfunihash \or
+ \expandafter\utfunichar \or
+ \expandafter\utfunisplit \or
+ \expandafter\utfuniboth \or
+ \expandafter\utfunihashchar \or
+ \expandafter\utfunihashsplit \or
+ \expandafter\utfunihashboth \or
+ \expandafter\utfuniglyphname \or
+ \expandafter\utfunientity \else
+ \expandafter\utfunihash
+ \fi}
+
+%D \startbuffer
+%D \enableregime[utf] \dostepwiserecurse{0}{8}{1}
+%D {\recurselevel:
+%D \chardef\utfunicodetracer=\recurselevel aap‒noot coördinatie – één
+%D \crlf}
+%D \stopbuffer
+%D
+%D \typebuffer \start \getbuffer \stop
+
+%D \macros
+%D {unicodehexnumber}
+%D
+%D A few auxiliary macros, producing the range||char pair:
+
+\def\unicodepair#1%
+ {\utfdiv{#1}:\utfmod{#1}}
+
+\def\unicodenumber#1{\number#1}
+
+\def\unicodehexnumber#1%
+ {\ifnum#1>\maxcard
+ \expanded{\uchexnumbers{\utfvid{#1}}}%
+ \expanded{\uchexnumbers{\utfdiv{\utfdiv{#1}}}}%
+ \else
+ 00%
+ \expanded{\uchexnumbers{\utfdiv{#1}}}%
+ \fi
+ \expanded{\uchexnumbers{\utfmod{#1}}}}
+
+%D The following macros visualize the unicode character. The
+%D \type {\relax} in front of the \type {-} prevents lookahead
+%D problems; somehow \type {\numexpr} cannot look beyond this
+%D sign, and expects a number.
+
+\def\utfunichar #1{{\tttf U\low{\tx\unicodenumber{#1}}}}
+\def\utfunisplit #1{{\tttf U\low{\tx\unicodepair{#1}}}}
+\def\utfuniboth #1{{\tttf U\low{\tx\unicodenumber{#1}->\unicodepair{#1}}}}
+\def\utfunientity #1{{\tttf\&\#x\unicodehexnumber{#1};}}
+
+%D The character itself is accessed and typeset by:
+%D
+%D \starttyping
+%D \def\utfunihash#1%
+%D {\executeifdefined{\@@univector\utfdiv{#1}}%
+%D \gobbleoneargument{\utfmod{#1}}}
+%D \stoptyping
+%D
+%D Again, we can provide a faster alternative, because inside
+%D the conditional executer, the argument is expanded twice,
+%D and therefore the calculation done once more than needed.
+%D So, we make sure that the argument is expansion on
+%D forehand. Just to remind you: \type {#1} is the \UNICODE\
+%D number.
+%D
+%D \starttyping
+%D \def\utfunihash#1%
+%D {\@EA\executeifdefined\@EA{\@EA\@@univector\number\utfdiv{#1}}%
+%D {\unknownchar\gobbleoneargument}{\utfmod{#1}}}
+%D \stoptyping
+%D
+%D In order to save calculation time, I decided to change
+%D this definition into:
+
+%D \starttyping
+%D \def\utfunihash#1%
+%D {\@EA\doutfunihash\@EA{\number\utfdiv{#1}}{#1}}
+%D
+%D \def\doutfunihash#1#2%
+%D {\ifcsname\@@univector\number#1\endcsname
+%D \csname\csname\@@univector#1\endcsname{\utfmod{#2}}\endcsname
+%D \else
+%D \unknownchar
+%D \fi}
+%D \stoptyping
+%D
+%D Or leaner and meaner:
+%D
+%D \starttyping
+%D \def\doutfunihash#1#2%
+%D {\csname
+%D \ifcsname\@@univector\number#1\endcsname
+%D \csname\@@univector#1\endcsname{\utfmod{#2}}%
+%D \else
+%D \@@unknownchar
+%D \fi
+%D \endcsname}
+%D \stoptyping
+%D
+%D And finaly it became:
+
+\def\doutfunihash#1#2%
+ {\ifcsname\@@univector\number#1\endcsname
+ \csname\@@univector#1\endcsname{\utfmod{#2}}%
+ \else
+ \@@unknownchar
+ \fi}
+
+\def\utfunihashglyph#1%
+ {\csname\@EA\doutfunihash\@EA{\number\utfdiv{#1}}{#1}\endcsname}
+
+\def\utfunihashcommand
+ {\@EAEAEA\string\utfunihashglyph}
+
+%D For practical purposes, we handle the normal \ASCII\
+%D characters here:
+
+\def\utfunihashglyph#1%
+ {\csname
+ \ifnum#1<\utf@i
+ \strippedcsname\unicodeasciicharacter\endcsname{#1}%
+ \else
+ \@EA\doutfunihash\@EA{\number\utfdiv{#1}}{#1}\endcsname
+ \fi}
+
+%D With:
+
+\let\unicodeasciicharacter\rawcharacter
+
+%D Now we can say:
+
+\let\utfunihash\utfunihashglyph
+
+%D We also need:
+
+\def\utfuniglyphname#1%
+ {{\tttf
+ \ifnum#1<\utf@i
+ \unicodeasciicharacter{#1}%
+ \else
+ \expandafter\string\csname\doutfunihash{\number\utfdiv{#1}}{#1}\endcsname
+ \fi}}
+
+%D The combined presentation is implemented by:
+
+\def\utfunihashchar #1%
+ {\utfunihash{#1}\low{\infofont\unicodenumber{#1}}}
+
+\def\utfunihashsplit#1%
+ {\utfunihash{#1}\low{\infofont\unicodepair{#1}}}
+
+\def\utfunihashboth #1%
+ {\utfunihash{#1}\low{\infofont\unicodenumber{#1}->\unicodepair{#1}}}
+
+%D Unknown characters get a placeholder.
+
+\unexpanded\def\unknownchar % {} prevents problems with arguments
+ {{\hbox{\vrule\!!width.5em\!!height1ex\!!depth\zeropoint}}}
+
+%D So far for the conversion macros. The optimizations we
+%D did, brought down the runtime some 50\%, which, given that
+%D the majority of characters will be normal \ASCII\
+%D characters, the penalty of conversion is not that large.
+
+%D \macros
+%D {useunicodevector}
+%D
+%D Since we end up with many encodings, it starts making
+%D sense to postpone loading, so let's start doing this
+%D with \UNICODE.
+
+\def\doifunicodevector#1%
+ {\doifdefined{\@@univector#1}}
+
+\def\useunicodevector[#1]%
+ {\processcommalist[#1]\douseunicodevector}
+
+\def\douseunicodevector#1%
+ {\ifundefined{\@@univector#1}%
+ \readsysfile{\f!unicprefix\threedigits{#1}}
+ {\writestatus{unicode}{loading vector #1}}
+ {\writestatus{unicode}{unknown vector #1}}%
+ \fi}
+
+%D \macros
+%D {startunicodevector}
+%D
+%D A vector roughly looks as follows. By putting the text
+%D inside the name constructor, we prevent problems with
+%D partial expansion in macros and special cases.
+%D
+%D \starttyping
+%D \startunicodevector 0
+%D \ifcase\numexpr(#1-159)\or
+%D \@@unknownchar\or % NO-BREAK SPACE
+%D exclamdown\or
+%D textcent\or
+%D ....\else
+%D \@@unknowncharacter
+%D \fi
+%D \stopunicodevector
+%D \stoptyping
+%D
+%D In vector \type {unix-000} you will find another
+%D optimizations. By using as less tokens as possible, we limit
+%D the time skipping branches in the test, and save upto 20\%
+%D runtime.
+
+\def\startunicodevector #1 #2\stopunicodevector
+ {\setgvalue{\@@univector#1}##1{#2}}
+
+%D We define (as a practical example) the utf signal FEFF:
+
+\ifx\zwnbsp\undefined
+ \let\zwnbsp\relax % zerowidthnonbreakablespace
+\fi
+
+\startunicodevector 254
+ \expandafter\strippedcsname\ifnum#1<255 \unknownchar\else\zwnbsp\fi
+\stopunicodevector
+
+%D Here we provide another auxiliary macro:
+%D
+%D \startbuffer
+%D \unicodeinfoline{196}{Ä}{LATIN CAPITAL LETTER A WITH DIAERESIS}
+%D \unicodeinfoline{197}{Å}{LATIN CAPITAL LETTER A WITH RING ABOVE}
+%D \unicodeinfoline{198}{Æ}{LATIN CAPITAL LETTER AE}
+%D \unicodeinfoline{199}{Ç}{LATIN CAPITAL LETTER C WITH CEDILLA}
+%D \unicodeinfoline{200}{È}{LATIN CAPITAL LETTER E WITH GRAVE}
+%D \unicodeinfoline{201}{É}{LATIN CAPITAL LETTER E WITH ACUTE}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \start \enableregime[utf]\getbuffer \stop
+
+\def\unicodeinfoline#1#2#3%
+ {\ifnum#1>\utf@g % 128
+ \noindent \hbox
+ {\hbox to 4em{\tttf\unicodehexnumber{#1}\hss}\quad
+ \hbox to 1em{#2\hss}\quad
+ \hbox to 9em{\tttf\unicodenumber{#1}->\unicodepair{#1}\hss}\quad
+ \hbox to 9em{\tttf\let\utfunihash\utfunihashcommand#2\hss}\quad % tricky
+ \lowercase {\tttf#3}}\par
+ \fi}
+
+%D The next code permits utf code in hyperlinks:
+
+\def\cleanunicodechar#1{.#1.}
+
+\appendtoks \let\unicodechar\cleanunicodechar \to \everycleanupfeatures
+
+%D We will now hook this mechanism in the existing font
+%D handler. More documentation will follow. Probably, some
+%D features in \type {font-uni.tex} will be generalized
+%D and moved here.
+
+\def\unidiv{0} \def\unimod{0}
+
+\chardef\utfunihashmode=0 % 0=hash glyph 1=font glyph
+
+\def\utfunifontglyph#1%
+ {\xdef\unidiv{\number\utfdiv{#1}}%
+ \xdef\unimod{\number\utfmod{#1}}%
+ \ifnum#1<\utf@i
+ \char\unimod % \unicodeascii\unimod
+ \else\ifcsname\@@univector\unidiv\endcsname
+ \csname\doutfunihash{\unidiv}{#1}\endcsname
+ \else % so, these can be different fonts !
+ \unicodeglyph\unidiv\unimod % no \uchar (yet)
+ \fi\fi}
+
+\chardef\utfunicommandmode=0 % 1 = hex
+
+\def\unicodecommandchar#1#2%
+ {\string\char
+ \ifcase\utfunicommandmode
+ #1:#2\else\lchexnumbers#1:\lchexnumbers#2%
+ \fi}
+
+\def\utfunifontcommand#1%
+ {\xdef\unidiv{\number\utfdiv{#1}}%
+ \xdef\unimod{\number\utfmod{#1}}%
+ \ifnum#1<\utf@i
+ \unicodecommandchar\unidiv\unimod
+ \else\ifcsname\@@univector\unidiv\endcsname
+ \@EA\string\csname\doutfunihash{\unidiv}{#1}\endcsname
+ \else
+ \unicodecommandchar\unidiv\unimod
+ \fi\fi}
+
+\def\utfunihash
+ {\ifcase\utfunihashmode
+ \@EA\utfunihashglyph
+ \else
+ \@EA\utfunifontglyph
+ \fi}
+
+\def\utfunihushcommand
+ {\@EAEAEA\string\utfunihashglyph}
+
+\def\utfunihashcommand
+ {\ifcase\utfunihashmode
+ % \@EA\@EAEAEA\@EA\string\@EA\utfunihashglyph
+ \@EA\utfunihushcommand
+ \else
+ \@EA\utfunifontcommand
+ \fi}
+
+%D We can convert from a number to some UTF code with the folowing
+%D conversion macro.
+
+% The first, na\"ive version:
+%
+% \def\numbertoutf#1%
+% {\ifnum#1<128
+% \rawcharacter{#1}%
+% \else\ifnum#1<2048
+% \rawcharacter{\the\numexpr192+#1/64\relax}%
+% \rawcharacter{\the\numexpr128+#1-(#1/64)*64\relax}%
+% \else % 3 bytes
+% \rawcharacter{\the\numexpr224+#1/4096\relax}%
+% \rawcharacter{\the\numexpr128+(#1-(#1/4096)*4096)/128\relax}%
+% \rawcharacter{\the\numexpr128+(#1-(#1/4096)*4096)+(#1-(#1/4096)*4096)/128\relax}%
+% \fi\fi}
+
+% We have to compensate for etex's rounding (thanks to Taco and
+% Nanning) for pointing/sorting this out:
+
+% \def\numbertoutf#1%
+% {\ifnum#1<128
+% \rawcharacter{#1}%
+% \else\ifnum#1<2048
+% \rawcharacter{\the\numexpr192+(#1-32)/64\relax}%
+% \rawcharacter{\the\numexpr128+(#1-((#1-32)/64)*64)\relax}%
+% \else
+% \rawcharacter{\the\numexpr224+(#1-2048)/4096\relax}%
+% \rawcharacter{\the\numexpr128+(#1-(((#1-2048)/4096)*4096)-32)/64\relax}%
+% \rawcharacter{\the\numexpr128+(#1-(((#1-2048)/4096)*4096)-((#1-(((#1-2048)/4096)*4096)-32)/64)*64)\relax}%
+% \fi\fi}
+
+\beginETEX \numexpr
+
+\chardef \utf@a= 64
+\mathchardef \utf@b= 4096
+\newcount\utf@c\utf@c=262144
+\chardef \utf@d= 192
+\chardef \utf@e= 224
+\chardef \utf@f= 240
+\chardef \utf@g= 128
+\mathchardef \utf@h= 256
+\chardef \utf@i= 127
+\mathchardef \utf@j= 2048
+\chardef \utf@k= 32
+
+\def\numbertoutf#1%
+ {\ifnum#1<\utf@g
+ \rawcharacter{#1}%
+ \else\ifnum#1<\utf@j
+ \rawcharacter{\the\numexpr\utf@d+(#1-\utf@k)/\utf@a\relax}%
+ \rawcharacter{\the\numexpr\utf@g+(#1-((#1-\utf@k)/\utf@a)*\utf@a)\relax}%
+ \else
+ \rawcharacter{\the\numexpr\utf@e+(#1-\utf@j)/\utf@b\relax}%
+ \rawcharacter{\the\numexpr\utf@g+(#1-(((#1-\utf@j)/\utf@b)*\utf@b)-\utf@k)/\utf@a\relax}%
+ \rawcharacter{\the\numexpr\utf@g+(#1-(((#1-\utf@j)/\utf@b)*\utf@b)-((#1-(((#1-\utf@j)/\utf@b)*\utf@b)-\utf@k)/\utf@a)*\utf@a)\relax}%
+ \fi\fi}
+
+\endETEX
+
+\beginTEX
+
+\def\numbertoutf#1%
+ {[\number#1]}
+
+\endTEX
+
+%D Goodies:
+
+\fetchruntimecommand \showunicodevector {\f!unicprefix\s!run}
+\fetchruntimecommand \showunicodetable {\f!unicprefix\s!run}
+
+%D Well, let's at least preload a few familiar ones. Here we
+%D also load the \UTF\ regime.
+
+\useunicodevector[0,1,2,3,4,5,30,32,33,34,39] \useregime[utf]
+
+% 31, text mem usage first
+
+\protect \endinput